C++'da bir nesnenin değer olarak bir işleve geçirilmesi sırasında kopyalama yapıcı kullanılarak nesnenin bir kopyası oluşturulur. Eğer sınıfta bir kullanıcı tanımlı kopyalama yapıcı belirtilmişse, işlevin geçici nesne-argümanını başlatmak için bu çağrılır. Belirtilmemişse — varsayılan derleyici kullanılır ve bu, bit düzeyinde kopyalama (shallow copy) gerçekleştirir.
Tuzaklar:
Örnek:
class StringWrapper { char* data; public: StringWrapper(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } // Hata: shallow copy StringWrapper(const StringWrapper& other) : data(other.data) {} ~StringWrapper() { delete [] data; } }; void foo(StringWrapper s) { // ... } int main() { StringWrapper s1("hello"); foo(s1); // UB!!! return 0; }
"Eğer bir işaretçi içeren sınıfta kopyalama yapıcıyı şöyle tanımlarsak:
MyClass(const MyClass &other) : data(other.data) {}? Bunun sonuçları neler olur?"
Doğru cevap: Bu kopyalama yapıcı, kopyalanan nesne ile aynı bellek alanına işaret eden bir nesne oluşturur. İki nesne yok edilirken bellek iki kez serbest bırakılacak (double free) ve bu da belirsiz bir davranışa yol açacaktır. Deep copy uygulamak gereklidir:
MyClass(const MyClass &other) { data = new int(*other.data); }
Hikaye
Büyük bir sunucu projesinde, içinde "ham" bir dizi bulunan nesnelerin konteynerleri kullanıldı ve standart kopyalama yapıcı (shallow copy) kullanıldı. Nesneler değer olarak geçirildiğinde double free meydana geldi ve uygulamanın çökmesine neden oldu, bu durum yalnızca üretimde yakalandı.
Hikaye
Eski bir C++ kütüphanesinde, grafik tamponunu kopyalamayan bir kopyalama yapısı, bir kopya üzerine değişiklik yapılırken diğerinin değişmesine neden oldu ve beklenmedik arayüz hatalarına yol açtı.
Hikaye
Bir işlevden değerle nesne dönerken, bir iç parola saklama sisteminde geçici nesne yok edildiğinde veriler temizlendi (shallow copy) ve sonuç olarak gerçek nesne sıfırlanmış bir işaretçi tuttu, sızıntı bir güvenlik denetimi sırasında tesadüfen ortaya çıktı.