SORU
21 NİSAN 2015, Salı


Neden CYBH davranış::memcpy TriviallyCopyable nesneler için tanımsız olur?

http://en.cppreference.com/w/cpp/string/byte/memcpy:

Eğer nesneleri TriviallyCopyable (örneğin, skaler, diziler, C-uyumlu yapılar) değilse, davranışı tanımsızdır.

Benim iş yerinde, uzun süre std::memcpy TriviallyCopyable kullanarak takas nesneleri bit için kullandık:

void swapMemory(Entity* ePtr1, Entity* ePtr2)
{
   static const int size = sizeof(Entity); 
   char swapBuffer[size];

   memcpy(swapBuffer, ePtr1, size);
   memcpy(ePtr1, ePtr2, size);
   memcpy(ePtr2, swapBuffer, size);
}

ve asla herhangi bir sorun yoktu.

Olmayan TriviallyCopyable nesnelerle std::memcpy istismar ve tanımsız davranış aşağı neden önemsiz olduğunu anlıyorum. Ancak, benim sorum:

Neden std::memcpy kendi davranış olmayan TriviallyCopyable nesnelerle kullanıldığı zaman tanımsız olur? Neden bir standart belirlemek için gerekli gördükleri?

GÜNCELLEME

http://en.cppreference.com/w/cpp/string/byte/memcpy içeriğini bu yazı ve yazılan cevaplara yanıt olarak değiştirildi. Mevcut açıklama diyor ki:

Eğer nesneler değildir TriviallyCopyable (örneğin, skaler, diziler, C-uyumlu yapılar), davranışı tanımsız sürece programa bağlı değil etkileri yıkıcı hedef nesne (aday tarafından memcpy) ve ömür boyu hedef nesne (ki sona erdi, ama başladı memcpy) tarafından başlatıldı bazı diğer araçlar gibi yerleştirme-yeni.

PS

@Cubbi: yorum

@Eğer bir şey İK aşağı garanti eğer RSahu, tüm programı tanımsız kılar. Ama Olası bu durumda İK etek ve cppreference buna göre değiştirilmiş gibi görünüyor katılıyorum.

CEVAP
21 NİSAN 2015, Salı


Bir zamanlar aynı türde başka bir nesne içine olmayan basit copyable türde bir nesne, temel bayt kopyalayınbu nesne hayatta değil.

Örnek:

std::string str;
std::string str2;
std::memcpy(&str2, &str, sizeof str);

Depolama yeniden kullanarak str2 ömrü sona erdi:

Bir program depolama yeniden kullanarak, herhangi bir nesnenin ömrü sona erebilir nesneyi kaplar veya açıkça yıkıcı çağırarak önemsiz olmayan bir yıkıcı bir sınıf türünde bir nesne. Bir nesne için önemsiz olmayan bir yıkıcı bir sınıf türü, program değil açıkça depolama bir yıkıcı çağırmak için gerekli nesneyi yeniden ya; ne kadar örtülü ölü nesneleri çağırır anlatıyor İK çağırmak] serbest kaplar

Ancakbu nesne diriltilecek değiliz:

ömür boyubir nesnenin bir nesne çalışma zamanı bir özellik. Bir nesne bir sınıf ise önemsiz olmayan başlatma söyleniyor ya da belli bir tip veya kendi üyelerinden biri tarafından başlatıldı kurucu önemsiz bir varsayılan kurucu dışında. [Not: yapıcı hareket/önemsiz bir kopyasını başlatma önemsiz değil başlatma.— not end]

Türünde bir nesne ömrü T başlar:

  • depolama ile türü için uygun uyum ve boyutu T elde edilen ve (1.2)
  • eğer nesne önemsiz olmayan başlatma, başlatma. tamamlayın.

Kod parçasında gördüğünüz gibi, önemsiz olmayan başlatma string - yani yapıcı bir çağrı ile ilişkili yapılmamıştır. Böylece nesne yaşıyor ve kullanım değeri veremeyiz.
[temel.tipleri]/2 /3 memcpy initializable çok basit copyable türleri için bytewise kopyalama tanımlayın:

Basit herhangi bir nesne (temel sınıf bir sınıfın bir başka) copyable yazın ya da nesnenin geçerli bir değeri olup olmadığını T, yazın T temel bayt (1.7) nesne uyduruyor olabilir char unsigned char dizisine kopyalanır. İçeriği ise char unsigned char dizi nesnesine kopyalar. nesne daha sonra orijinal değerini tutacaktır. [Örnek:

#define N sizeof(T)
char buf[N];
T obj;                     // obj initialized to its original value
std::memcpy(buf, &obj, N); // between these two calls to std::memcpy,
                           // obj might be modified
std::memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type 
                           //holds its original value

— son örnek]

Basit copyable herhangi bir türü için T işaret etmek için iki işaretçiler T, 25* *farklı obj1 obj2 nerede ne obj1 ne de nesneler obj2 taban sınıf bir sınıfın, temel bayt (1.7) yapıyor obj1 obj2, obj2 sonradan tutacaktır kopyalanır kadar obj1ile aynı değer.[Örnek:

T* t1p;
T* t2p;
  // provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
  // at this point, every subobject of trivially copyable type in *t1p contains
  // the same value as the corresponding subobject in *t2p

— son örnek]

Bu gibi görünüyor değil pek tutarlı ile yukarıdaki alıntı hakkında ömür boyu: değiliz arama *t1p'In kopyası yapıcısı (veya herhangi bir decimal için bu konuda), ama görünüşe göre hazır için keyfi bir şekilde kullanılması, gibi *t2p. Ancak, bu paragraf bu tanım zaten atlatmak gibi görünüyor.

Son olarak, kütüphane/derleyici mümkün olduğunu kaydetti ve basit copyable türleri için bazı standart kütüphane algoritmaları optimize etmek için izin alınması gerekmektedir.Basit copyable türleri işaretçiler std::copy temel bayt memcpy çağırabilir. Bu da swap için de geçerlidir.
Bu yüzden sadece sopa kullanarak normal genel algoritmalar ve izin derleyici herhangi bir uygun düşük seviyeli optimizasyon - bu kısmen ne düşüncem basit copyable türü icat edildi için ilk başta: Belirleyici yasallık bazı iyileştirmeler. Ayrıca, bu dilin çelişkili ve underspecified parçaları hakkında endişelenmenize gerek beynin zarar önler.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Bennythecoder

    Bennythecode

    25 Mart 2008
  • khloe brooks

    khloe brooks

    25 Temmuz 2011
  • UrAvgConsumer

    UrAvgConsume

    1 Ocak 2012