C++ Dilinde Taşıma Semantiği
- Yusuf Hançar
- May 29, 2024
- 2 min read
Başarılı ve verimli bir yazılım geliştirme sürecinde, nesnelerin yönetimi önemli bir rol oynar. Kullanılmayacak bir nesne olduğunda, bu nesneyi başka bir nesneye kopyalamak yerine kaynağını taşıyarak (move semantics) daha etkili bir kod kullanmak mümkündür. Bu yaklaşım, özellikle performans açısından büyük avantajlar sağlar.
Modern C++ programlamasında, taşınma yapıcıları (move constructors) bazı durumlarda derleyici tarafından otomatik olarak oluşturulur. Eğer beklenen şekilde çalışıyorlarsa, bu en kullanışlı yöntemdir ve "sıfır kuralı" (rule of zero) olarak adlandırılan prensip doğrultusunda hareket edilmesini sağlar. Bu prensibe göre, bir handle (yani bir pointer ya da reference) kullanılmadığında, derleyici bu yapıcıları bizim yazacağımız şekilde otomatik olarak oluşturur.
Taşıma semantiği, büyük ve maliyetli nesnelerin verimli bir şekilde yönetilmesini sağlar. Taşıma yapıcıları ve taşıma atama operatörleri, kaynakların kopyalanması yerine mevcut kaynağın mülkiyetini yeni nesneye devreder. Bu, özellikle büyük veri yapıları veya dinamik bellek yönetimi gerektiren sınıflar için performans artışı sağlar.
Atama işlemi gerçekleştirilirken derleyici, semantik yapılara bakarak, kopyalama veya taşıma işlemleri için uygun olan özel üye fonksiyonlarını çağırarak işlemi tamamlayacaktır. Bu sayede, kodumuzun daha verimli ve okunabilir olmasını sağlayarak yazılım geliştirme sürecini optimize edebiliriz.
Fonksiyonlar sınıf türünden dönüş değerine sahip olduklarında const olarak döndürmek taşıma semantiği ve copy elision söz konusu olduğunda move üye fonksiyonların çağırılmasını engelleyebilmektedir.
class SmartCode {
public :
SmartCode(){ cout << "default ctor" << endl; }
SmartCode(int){ cout << "SmartCode(int)" << endl; }
SmartCode(const SmartCode&){ cout << "copy ctor" << endl; }
SmartCode(SmartCode&&){ cout << "move ctor" << endl; }
SmartCode& operator=(const SmartCode&)
{
cout << "copy assignment" << endl;
return *this;
}
SmartCode& operator=(SmartCode&&)
{
cout << "move assignment" << endl;
return *this;
}
};
const SmartCode foo(int param)
{
SmartCode val(param);
return val;
}
int main()
{
SmartCode sc;
sc = foo(23);
}
******************************
CEVAP : def ctor
SmartCode(int)
copy assignment
******************************
AÇIKLAMA : const anahtar kelimesi, nesnenin taşınmasını (move) engeller. Çünkü taşınabilir bir nesne üzerinde değişiklikler yapılabilmelidir, ancak const bir nesne değiştirilemez. Bu nedenle, const olarak tanımlanan bir nesne sadece kopyalanabilir, taşınamaz.Bu yüzden, move assignment yerine copy assignment çağrılır. const olmasaydı move assignment çağırılırdı.
******************************
Fonksiyonun geri dönüş değeri ifadesinde std::move kullanılmamalıdır. Bu duruma pessimistic move denilir.
SmartCode foo()
{
SmartCode val;
return std::move(val);
}
int main()
{
auto sc = foo();
}
******************************
CEVAP : def ctor
move ctor
******************************
AÇIKLAMA : copy elision engellendi move member çağırıldı.
******************************
SmartCode foo()
{
SmartCode val;
return val;
}
int main()
{
auto sc = foo();
}
******************************
CEVAP : def ctor
******************************
AÇIKLAMA : copy elision gerçekleti.
******************************
int main()
{
SmartCode sc{ 23 };
SmartCode mx = sc;
}
******************************
CEVAP : SmartCode(int)
copy ctor
******************************
AÇIKLAMA : bu durumda kaynak çalınmaz kopyalanır.
******************************
int main()
{
SmartCode sc{ 23 };
SmartCode mx = std::move(sc);
}
******************************
CEVAP : SmartCode(int)
move ctor
******************************
AÇIKLAMA : bu durumda kaynak çalınır.
******************************
Comments