2013-04-08 20 views
6

C++ taslak durumları:kopyalama elision ve geçici bağlı-ile-ref nesne

12.8p31 kopya elision adı kopya/taşıma işlemlerinin bu elision, kombine edilebilen (aşağıdaki durumlarda izin verilir,) birden fazla kopya ortadan kaldırmak:

(...)

geçici bir sınıf nesnesi başvuru (12.2 bağlı edilmemiştir
  • ) kopyalanmak olurdu/taşındı Aynı ev-niteliksiz tip bir sınıf nesnesi 0, kopyalama/taşıma işlemi ihmal kopya hedef doğrudan geçici bir nesne oluşturmak tarafından ihmal edilebilir/diğer bir deyişle

hareket:

X MakeX() { 
    return X(); // Copy elided 
} 

X MakeX() { 
    const X& x = X(); // Copy not elided 
    return x; 
} 

referansları için bu tür bir kısıtlamanın nedeni nedir? onlar geçici ve referans arasındaki farkı (IMHO) görmek için başarısız olduğunu örneklemek için sadece oldukları gibi

, aşağıdaki örnekler geçerliliği odaklanmak etmeyin.

Referans tanıtımı ile bir yandan diğer eşlerin aynı nesneyi takmalarına izin verdik, MakeX() numaralı telefon arayan kişi güvenli ve temiz olmasını bekliyor.

class Y { 
public: 
    Y(const X& x) : _xRef(x) {} 
private: 
    const X& _xRef; 
}; 

X MakeX() { 
    const X& x = X(); 
    Y y{x}; 
    StaticStuff::send(y); 
    return x; // Oops, I promised to return a clean, 
       // new object, but in fact it might be silently 
       // changed by someone else. 
} 

Ancak bu dava hakkında (muhtemelen UB var;) kadar):

class Y { 
public: 
    Y(X* x) : _xPtr(x) {} 
private: 
    X* _xRef; 
}; 

X MakeX() { 
    X x; 
    Y y{&x}; // I'm referencing a local object but I know it will be 
      // copy elided so present in the outer stack frame. 
    StaticStuff::send(y); 
    return x; // Copy elided? 
} 
+2

'StaticStuff :: (y) gönderme;' aslında değiştirme imkanı getirmemektedir 'dolaylı => o MakeX'' sonunda x' 'için bir başvuru kullanımı Tanımsız bir davranış x'. –

+1

'Hatalar, temiz, yeni bir nesne döndürmeye söz verdim, ama aslında başka biri tarafından sessizce değiştirilmiş olabilir. '- ne demek istiyorsun? 'x', const X’dir ve bu nedenle değiştirilemez. –

+0

MakeX' 'sizin ikinci versiyonu muhtemelen' const X & '' X' bir ova dönüşme kopya kurucu çağırmak istiyorum, sorun olması? – didierc

cevap

3

Asla bir kopyası elided edilecektir biliyorum. Kopyalama hiçbir zaman zorunlu değildir. Bu nedenle, her iki durumda da UB veya hiç yoktur. Bu, StaticStuff:send'un ilettiğiniz nesneyle ne yaptığına bağlı olarak değişir. y._xRef veya *y._xPtr için herhangi bir poitner/başvuru korursa, MakeX() döndükten sonra bu işaretçinin/referansın geri döndürülmesi, orijinal nesne x orijinal nesnesi olduğu için UB'ye neden olur MakeX() içinde süresi ve ömrü sona ermiştir.

Bu UB'nin sonucunun "her şey gayet iyi çalışıyor" olması olasıdır çünkü kopyalama ellemesi gerçekleşti ve işaretçi/başvuru örneği "dış yığın çerçevesi" örneğine başvurur. Ancak, bu kesinlikle tesadüf ve hala UB.

+0

Standart, "Seçime (...) * izin verildiğini" söylerler. "Bu yüzden hiçbir şey bekleyemem ve evet, bu iki durumda UB-topraklarına giriyorum. Söylemek istediğim şey, geçici bir durumken, const ref'in (geçici olarak kalmasını sağlayan tek yol) izin verilmemesinin özel bir nedenini görmüyorum. –

+0

Bunun çok doğru olduğunu sanmıyorum, en azından C++ 11'de değil. Ya X 'hareket ettirilebilir, ancak kopyalanabilir değil mi? Daha sonra OP'nin ilk örneği hala derlenecek ve derleyici bir "hareket elesyonu" yapmak zorunda kalacak, değil mi? Lütfen ayrıca http://stackoverflow.com/questions/18609968/is-default-constructor-elision-assignment-elision-possible-in-principle ayrıntılarına da göz atabilirsiniz. – eold

+0

@leden Takip etmiyorum. ** zorlamak için ** bir zorunluluk yoktur. Bunlar * her zaman * isteğe bağlıdır. – Angew