2016-01-27 31 views
6

aşağıdaki programı ele alalım ctor kopyalayın:dönersek geçicileri/

#include<iostream> 
using namespace std; 

struct S 
{ 
    S() = default; 
    S(const S& other) = delete; 
    S(S&& other) = delete; 
    int i; 
}; 

S nakedBrace() 
{ 
    return {}; // no S constructed here? 
} 

S typedBrace() 
{ 
    return S{}; 
} 

int main() 
{ 
    // produce an observable effect. 
    cout << nakedBrace().i << endl; // ok 
    cout << typedBrace().i << endl; // error: deleted move ctor 
} 

Numune oturumu:

$ g++ -Wall -std=c++14 -o no-copy-ctor no-copy-ctor.cpp 
no-copy-ctor.cpp: In function 'S typedBrace()': 
no-copy-ctor.cpp:19:12: error: use of deleted function 'S::S(S&&)' 
    return S{}; 
      ^
no-copy-ctor.cpp:8:5: note: declared here 
    S(S&& other) = delete; 

Bu gcc nakedBrace() kabul ettiğini beni hayrete düşürüyor. Kavramsal olarak iki fonksiyonun eşdeğer olduğunu düşündüm: Geçici bir S inşa edildi ve geri döndü. Kopyalama işlemi gerçekleştirilebilir veya gerçekleştirilemez, ancak taşıma veya fotokopi kağıdının (her ikisi de burada silinir) yine de standart tarafından belirtildiği gibi erişilebilir olması gerekir (12.8/32).

Bu, nakedBrace()'un hiçbir zaman bir S? Ya da, küme-başlatma ile doğrudan geri dönüş değeri yapar, böylece hiçbir kopya hareket/ctor kavramsal olarak gerekli değildir?

cevap

4

Bu, standart bir davranıştır.

N4140 [stmt.return]/2: [...] bir çaprazlı-init-listesi ile dönüş deyim nesnesi veya referans belirtilen başlatıcısı kopya listesi-başlatma (8.5.4) ile işlevi döndürülecek başlatır liste. [...]

Bu ve typedBrace tarafından gerçekleştirilen başlatımı bu eşdeğer olduğu anlamına gelir

:

S nakedBrace = {}; //calls default constructor 
S typedBrace = S{}; //calls default, then copy constructor (likely elided) 
1

[stmt.return]/2 ... dönüş void olmayan bir ifadeyle ifade, yalnızca bir değer döndüren işlevlerde kullanılabilir; İfadenin değeri, işlevin arayıcıya döndürülür. İfadenin değeri, göründüğü işlevin dönüş türüne dolaylı olarak dönüştürülür. Bir dönüş beyanı, geçici bir nesnenin (12.2) yapımı ve kopyalanmasını veya taşınmasını içerebilir ... kaşeli-başlangıç ​​listesi ile bir iade ifadesi, kopya listesinin başlatılmasıyla işlevden döndürülen nesneyi veya referansı başlatır. Belirtilen başlatıcı listesinden (8.5.4).

[class.temporary] sınıfı türü/1 Temporaries çeşitli bağlamlarda oluşturulur: ... Bir prvalue (6.6.3) dönen ...

Yani evet, bildiğim kadarıyla I olarak söyleyebilirim, anlamsal bir fark var. typedBrace, S türünde bir değer üreten S{} ifadesini değerlendirir, sonra bu ifadeden dönüş değerini kopyala-oluşturmaya çalışır. bunun yerine dönüş değerini doğrudan parantez içinde init listesinden oluşturur.

S s{}; (işleri) ile S s = S{}; (çalışmıyor) ile aynı durum, biraz dolaylı olarak bir yere gizlenmiştir.

İlgili konular