Fethi Polat 1
Fethi Polat
TuZaKK 1
TuZaKK
xranzei 1
xranzei
Agresifizm 1
Agresifizm
Bvural41 1
Bvural41
noisiv 1
noisiv
Manwe Work 1
Manwe Work
Hikaye Ekle

TEMP_BUFFER Copy/Move Problem

Ayyıldız2 | 2008 TR Yapısı • 1-99 Orta Emek Destan • Oto Avsız • 10 Temmuz 21:00 HEMEN TIKLA!

Bu arada yazıda söylemeyi unutmuşum, copy assignment operatorda copy-swap idiomu tercih edilebilir, ben special member funcları örnek olarak basitçe yazdım çok takılmayın, kullanacaksanız implementasyonu size kalmış buffer_new vb. API'lara bakmadan hareket etmeyin sorumluluk size ait
 
Eline sağlık, analiz baya iyi olmuş. Shallow copy + objeyi tekrar pool’a bırakma senaryosunda double-free ve free list’in bozulması zaten en klasik patlayan şeylerden biri. Crash’in gidip alakasız yerde çıkması da tam beklenen durum.Copy’yi direkt delete etmek burada yeterli gibi duruyor. Move tarafını da iyi yakalamışsın user-defined dtor olunca implicit move’un devreye girmemesi gözden kaçabiliyor çünkü, Deep copy’de read_point ile flag state’lerinin taşınmaması detayı da kritikmiş. İnsan normal kopya sanıp kullanır, sonra niye böyle davranıyor diye uğraşır. Repoda çok copy kullanımı yok gibi ama yine de resource yöneten diğer class’ları bir taramak mantıklı olur. Godbolt örneği de olayı direkt anlaşılır hale getirmiş.

Repoda çok copy kullanımı yok gibi ama yine de resource yöneten diğer class’ları bir taramak mantıklı olur.
Şu kısımda büyük bi patladım hakkını helal et asfmklasdgömklasdglasdg forum bayağı seviye atlamış AI çıktığından beri. Bu gidişte metin2'yi unreal'da falan da çalıştıracaklar az kaldı xDD
 
sıra bende

Eline sağlık, tespit bence doğru. TEMP_BUFFER burada value-semantic bir tip gibi değil, ownership taşıyan geçici bir RAII wrapper gibi davranıyor. Bu yüzden benim de ilk tercihim deep copy yazmak değil, copy ctor ve copy assignment’ı tamamen kapatmak olurdu.

TEMP_BUFFER(const TEMP_BUFFER&amp;) = delete;<br>TEMP_BUFFER&amp; operator=(const TEMP_BUFFER&amp;) = delete;<br>
Çünkü deep copy yazınca sınıfa “kopyalanabilir ve aynı state’i korur” anlamı yüklenmiş oluyor. Ama senin de not düştüğün gibi read point, flag/state vb. her şey birebir taşınmıyorsa bu sefer başka bir yanıltıcı davranış doğabilir. TEMP_BUFFER paket oluşturma tarafında geçici buffer gibi kullanılıyorsa copy-delete çok daha net ve güvenli.

Move tarafı için de uyarın yerinde. User-declared destructor olduğu için move ctor / move assignment otomatik gelmiyor. Copy’leri delete edince sınıf move da edilemiyorsa, ileride std::move, return value, fluent kullanım veya container içinde kullanım gibi yerlerde patlayabilir. O yüzden gerçekten taşınması gerekiyorsa explicit move yazmak mantıklı.

Bir de deep copy tercih edilecekse copy assignment kısmında küçük bir exception-safety notu var: mevcut buf önce delete edilip sonra yeni buffer alınıyor. buffer_new / buffer_write tarafında başarısızlık ihtimali varsa nesne yarım state’te kalabilir. Daha güvenli yaklaşım önce yeni buffer’ı oluşturup yazmak, her şey başarılı olduktan sonra eski buffer’ı bırakmak veya copy-and-swap tarzı gitmek olur.

Özetle TEMP_BUFFER için bence en doğru çözüm:

TEMP_BUFFER(const TEMP_BUFFER&amp;) = delete;<br>TEMP_BUFFER&amp; operator=(const TEMP_BUFFER&amp;) = delete;<br><br>TEMP_BUFFER(TEMP_BUFFER&amp;&amp;) noexcept;<br>TEMP_BUFFER&amp; operator=(TEMP_BUFFER&amp;&amp;) noexcept;<br>
Uzun vadede de raw LPBUFFER sahipliğini doğrudan sınıfta taşımak yerine custom deleter’lı unique_ptr benzeri bir handle/wrapper yazmak daha temiz olur. Böylece “bu kaynak kime ait, kim release edecek, kopyalanabilir mi?” soruları koddan daha net okunur.

Kısacası sorun hayati olmasa bile tespit doğru: kaynak yöneten sınıflarda compiler’ın ürettiği copy special member’lara güvenmek genelde saatli bomba.
 
sıra bende

Eline sağlık, tespit bence doğru. TEMP_BUFFER burada value-semantic bir tip gibi değil, ownership taşıyan geçici bir RAII wrapper gibi davranıyor. Bu yüzden benim de ilk tercihim deep copy yazmak değil, copy ctor ve copy assignment’ı tamamen kapatmak olurdu.

TEMP_BUFFER(const TEMP_BUFFER&amp;) = delete;<br>TEMP_BUFFER&amp; operator=(const TEMP_BUFFER&amp;) = delete;<br>
Çünkü deep copy yazınca sınıfa “kopyalanabilir ve aynı state’i korur” anlamı yüklenmiş oluyor. Ama senin de not düştüğün gibi read point, flag/state vb. her şey birebir taşınmıyorsa bu sefer başka bir yanıltıcı davranış doğabilir. TEMP_BUFFER paket oluşturma tarafında geçici buffer gibi kullanılıyorsa copy-delete çok daha net ve güvenli.

Move tarafı için de uyarın yerinde. User-declared destructor olduğu için move ctor / move assignment otomatik gelmiyor. Copy’leri delete edince sınıf move da edilemiyorsa, ileride std::move, return value, fluent kullanım veya container içinde kullanım gibi yerlerde patlayabilir. O yüzden gerçekten taşınması gerekiyorsa explicit move yazmak mantıklı.

Bir de deep copy tercih edilecekse copy assignment kısmında küçük bir exception-safety notu var: mevcut buf önce delete edilip sonra yeni buffer alınıyor. buffer_new / buffer_write tarafında başarısızlık ihtimali varsa nesne yarım state’te kalabilir. Daha güvenli yaklaşım önce yeni buffer’ı oluşturup yazmak, her şey başarılı olduktan sonra eski buffer’ı bırakmak veya copy-and-swap tarzı gitmek olur.

Özetle TEMP_BUFFER için bence en doğru çözüm:

TEMP_BUFFER(const TEMP_BUFFER&amp;) = delete;<br>TEMP_BUFFER&amp; operator=(const TEMP_BUFFER&amp;) = delete;<br><br>TEMP_BUFFER(TEMP_BUFFER&amp;&amp;) noexcept;<br>TEMP_BUFFER&amp; operator=(TEMP_BUFFER&amp;&amp;) noexcept;<br>
Uzun vadede de raw LPBUFFER sahipliğini doğrudan sınıfta taşımak yerine custom deleter’lı unique_ptr benzeri bir handle/wrapper yazmak daha temiz olur. Böylece “bu kaynak kime ait, kim release edecek, kopyalanabilir mi?” soruları koddan daha net okunur.

Kısacası sorun hayati olmasa bile tespit doğru: kaynak yöneten sınıflarda compiler’ın ürettiği copy special member’lara güvenmek genelde saatli bomba.
benim kartın limiti dolmuş o yüzden kendi bilgimi kullanarak yorum yapmam gerekiyor. kendi bilgimle de uzun bir inceleme yapmaya üşeniyorum. zaten bu konu hakkında çokta bilgi sahibi değilim o yüzden elimden sadece teşekkür etmek geliyor. @Larry Watterson eline sağlık teşekkürler.
 
sıra bende

Eline sağlık, tespit bence doğru. TEMP_BUFFER burada value-semantic bir tip gibi değil, ownership taşıyan geçici bir RAII wrapper gibi davranıyor. Bu yüzden benim de ilk tercihim deep copy yazmak değil, copy ctor ve copy assignment’ı tamamen kapatmak olurdu.

TEMP_BUFFER(const TEMP_BUFFER&amp;) = delete;<br>TEMP_BUFFER&amp; operator=(const TEMP_BUFFER&amp;) = delete;<br>
Çünkü deep copy yazınca sınıfa “kopyalanabilir ve aynı state’i korur” anlamı yüklenmiş oluyor. Ama senin de not düştüğün gibi read point, flag/state vb. her şey birebir taşınmıyorsa bu sefer başka bir yanıltıcı davranış doğabilir. TEMP_BUFFER paket oluşturma tarafında geçici buffer gibi kullanılıyorsa copy-delete çok daha net ve güvenli.

Move tarafı için de uyarın yerinde. User-declared destructor olduğu için move ctor / move assignment otomatik gelmiyor. Copy’leri delete edince sınıf move da edilemiyorsa, ileride std::move, return value, fluent kullanım veya container içinde kullanım gibi yerlerde patlayabilir. O yüzden gerçekten taşınması gerekiyorsa explicit move yazmak mantıklı.

Bir de deep copy tercih edilecekse copy assignment kısmında küçük bir exception-safety notu var: mevcut buf önce delete edilip sonra yeni buffer alınıyor. buffer_new / buffer_write tarafında başarısızlık ihtimali varsa nesne yarım state’te kalabilir. Daha güvenli yaklaşım önce yeni buffer’ı oluşturup yazmak, her şey başarılı olduktan sonra eski buffer’ı bırakmak veya copy-and-swap tarzı gitmek olur.

Özetle TEMP_BUFFER için bence en doğru çözüm:

TEMP_BUFFER(const TEMP_BUFFER&amp;) = delete;<br>TEMP_BUFFER&amp; operator=(const TEMP_BUFFER&amp;) = delete;<br><br>TEMP_BUFFER(TEMP_BUFFER&amp;&amp;) noexcept;<br>TEMP_BUFFER&amp; operator=(TEMP_BUFFER&amp;&amp;) noexcept;<br>
Uzun vadede de raw LPBUFFER sahipliğini doğrudan sınıfta taşımak yerine custom deleter’lı unique_ptr benzeri bir handle/wrapper yazmak daha temiz olur. Böylece “bu kaynak kime ait, kim release edecek, kopyalanabilir mi?” soruları koddan daha net okunur.

Kısacası sorun hayati olmasa bile tespit doğru: kaynak yöneten sınıflarda compiler’ın ürettiği copy special member’lara güvenmek genelde saatli bomba.
Custom deleter için duruma göre stateless bir lambda veya functor yazılabilirse maliyet olmayacağından(deleter state taşırsa veya function pointer kullanılırsa boyut büyür) olabilir, tasarım açısından ve prod'da pek tercih ettiğim bir yöntem değil ama metin2 için olabilir, neden olmasın..

copy-swap idiom evet bir üstteki yorumda yazmıştım, konuda belirtmeyi atlamışım, yorum için teşekkürler
 

Şu an konuyu görüntüleyenler (Toplam : 4, Üye: 1, Misafir: 3)

Geri
Üst