ProgramlamaC++ Geliştirici

Yüzeysel kopya ile derin kopya arasındaki farkı açıklayın, dinamik bellek içeren sınıflar için. Derin kopyalama yapıcıya ne zaman ve neden ihtiyaç vardır? Derin kopyayı manuel olarak nasıl uygulayabilirsiniz?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Sorunun Tarihi

C++'ta nesneleri kopyalarken başlangıçta üye bazında kopyalama mekanizması kullanılır: her nesne üyesi için kendi kopyalama işlemi çağrılır. Yerleşik türler için bu güvenlidir, ancak dinamik kaynaklar için bir sorun ortaya çıkar: yalnızca işaretçiler kopyalanır, veriler değil.

Sorun

Eğer nesne, heap bellekte tahsis edilmiş bir bellek alanına işaret eden bir işaretçi içeriyorsa, iki nesne kopyalandıktan sonra aynı bellek alanına işaret edeceklerdir. Bu durumda bir nesne yok edildiğinde bellek serbest bırakılacak ve diğerinin işaretçisi geçersiz hale gelecektir ("yabancı" işaretçi). Bu, çalışma zamanı hatalarına ve bellek sızıntılarına yol açar.

Çözüm

Kopyanın bağımsız olması için derin kopyalama gereklidir — bayt bazında kopyalama ve kendi tamponunun tahsis edilmesi gerekir. Bu, özel bir kopyalama yapıcı ve atama operatörü yazarak gerçekleştirilir.

Kod örneği:

class MyString { char* data; public: MyString(const char* s) { data = new char[strlen(s)+1]; strcpy(data, s); } // Derin kopyalama yapıcı MyString(const MyString& src) { data = new char[strlen(src.data) + 1]; strcpy(data, src.data); } // Derin kopyalama atama MyString& operator=(const MyString& src) { if (this != &src) { delete[] data; data = new char[strlen(src.data) + 1]; strcpy(data, src.data); } return *this; } ~MyString() { delete[] data; } };

Anahtar özellikler:

  • Dış kaynakları yöneten sınıflar için gereklidir
  • Kendi kopyalama yapıcılarını ve operator= yöntemini uygulamak gereklidir
  • Üç Kuralı doğru şekilde uygulanmazsa bellek sızıntıları olabilir

Aldatıcı Sorular.

Sınıf sadece işaretçi içeriyorsa ve bellek tahsis edilmiyorsa, neden özel bir yıkıcıya ihtiyaç var?

Yıkıcı, sınıf içinde bellek (veya başka bir kaynak) açık şekilde tahsis ettiyseniz gereklidir. Eğer işaretçi bellek tahsis etmiyorsa, varsayılan yıkıcı yeterlidir.


Dinamik bellek içeren bir sınıfta operator= uygulanmazsa ve kopyalama yapıcı tanımlanmışsa ne olur?

Eğer kopyalama yapıcısını manuel olarak tanımladıysanız, derleyici operator= yöntemini otomatik olarak uygulamaz; ya örtük olarak tanımlanır ya da derleyici hata/uyarı verir (standartlara bağlıdır). Bu, atama sırasında kötü tanımlanmış davranışa yol açar: üye bazında kopyalama gerçekleşir ve çift serbest bırakma veya bellek sızıntısı oluşur.

Kod örneği:

MyString a("hi"); MyString b = a; // Tamam: sizin kopyalama yapıcınız MyString c("bye"); c = a; // Problem! Eğer operator= manuel olarak uygulanmamışsa, yüzeysel kopyalama oluşacak

Kendisine atama yaparken manuel olarak operator= uygulamanın tehlikesi nedir?

Kaynakları paylaşırken this!=&rhs kontrolü yapılmadan kendisine atama yapıldığında, delete[] data çalıştırılacak ve ardından zaten yok edilmiş dizinin kopyalanması gerçekleşecektir, bu da segfault'a neden olur. Kendini koruma: her zaman self-assignment'ı kontrol edin.

if (this != &rhs) { ... }

Tipik Hatalar ve Anti-Desenler

  • Üç Kural yöntemlerinden biri (kopyalama yapıcı, operator=, yıkıcı) uygulanmamıştır
  • Kendine atama kontrolü yapılmamaktadır
  • Unutulan delete[] ile bellek sızıntısı
  • Ortak işaretçiler ile çift serbest bırakma

Gerçek Hayat Örneği

Olumsuz Durum

Geliştirici, derin kopyalama uygulamadan, yerleşik işaretçiye sahip bir sınıf nesnesini kopyalar. Kopyalama sonrasında birkaç nesne, tek bir bellek alanını paylaşır. İki yıkıcı çift serbest bırakmayı tetikler, programın çökmesine neden olur.

Artılar:

  • Kodu yazmak kolaydır (ilk bakışta "kopyalama çalışıyor")

Eksiler:

  • Program çökmesi, öngörülemeyen hatalar
  • Bellek sızıntıları veya çift serbest bırakma

Olumlu Durum

Geliştirici, kopyalama yapıcısını, atama operatörünü ve yıkıcıyı düzgün bir şekilde uygular. Her nesne kendi belleğine sahiptir.

Artılar:

  • Kopyalama ve yok etme sırasında güvenlik
  • Bellek sızıntısı yok

Eksiler:

  • Çok sayıda kopya sırasında kopyalama yükü artar