2016-01-27 10 views
6

निम्नलिखित कार्यक्रम पर विचार करें:रिटर्निंग temporaries/कॉपी ctor

#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 
} 

नमूना सत्र:

$ 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; 

यह मुझे हैरान है कि जीसीसी nakedBrace() स्वीकार करता है। मैंने सोचा कि अवधारणात्मक रूप से दो कार्य समकक्ष हैं: अस्थायी S का निर्माण और लौटाया गया है। प्रतिलिपि कॉपी करें या नहीं किया जा सकता है, लेकिन मानक (12.8/32) के अनुसार, चाल या प्रतिलिपि ctor (दोनों को यहां हटा दिया गया है) अभी भी सुलभ होना चाहिए।

क्या इसका मतलब है कि nakedBrace() कभी एस नहीं बनाता है? या यह करता है, लेकिन सीधे ब्रेस-प्रारंभिकरण के साथ वापसी मूल्य में, ताकि कोई प्रतिलिपि/ctor अवधारणात्मक रूप से आवश्यक न हो?

उत्तर

4

यह मानक व्यवहार है।

N4140 [stmt.return]/2: [...] एक braced-init-सूची के साथ एक वापसी कथन initializes वस्तु या संदर्भ निर्दिष्ट प्रारंभकर्ता से कॉपी-सूची-प्रारंभ (8.5.4) द्वारा समारोह से वापस करने सूची। [...]

इसका मतलब है कि initializations और typedBrace द्वारा किए गए इन के बराबर हैं:

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

[stmt.return]/2 ... एक वापसी गैर-शून्य प्रकार की अभिव्यक्ति के साथ कथन का उपयोग केवल मूल्य को वापस करने वाले कार्यों में किया जा सकता है; अभिव्यक्ति का मूल्य फ़ंक्शन के कॉलर पर वापस कर दिया जाता है। अभिव्यक्ति का मूल्य पूरी तरह से उस फ़ंक्शन के रिटर्न प्रकार में परिवर्तित होता है जिसमें यह प्रतीत होता है। एक रिटर्न स्टेटमेंट में अस्थायी ऑब्जेक्ट (12.2) के निर्माण और प्रतिलिपि या स्थानांतरित हो सकते हैं ... ब्रेस्ड-इनिट-लिस्ट के साथ एक रिटर्न स्टेटमेंट कॉपी-सूची-प्रारंभिकरण द्वारा फ़ंक्शन से वापस आने के लिए ऑब्जेक्ट या संदर्भ को प्रारंभ करता है (8.5.4) निर्दिष्ट प्रारंभकर्ता सूची से।

[class.temporary] वर्ग प्रकार के/1 temporaries विभिन्न संदर्भों में बनाई गई हैं: मैं के रूप में ... एक prvalue (6.6.3) पर वापस आ ...

तो हाँ, जहाँ तक बता सकते हैं, एक अर्थपूर्ण अंतर है। typedBrace एक अभिव्यक्ति S{}, जो प्रकार S के prvalue का उत्पादन का मूल्यांकन करता है, तो वह अभिव्यक्ति से अपनी वापसी मान की प्रतिलिपि-निर्माण करने के लिए प्रयास करता है। इसके बजाय ब्रेसिड-इनिट-लिस्ट से सीधे इसके वापसी मूल्य को बनाता है।

यह वही स्थिति है जैसे S s{}; (काम करता है) बनाम S s = S{}; (काम नहीं करता), बस कुछ हद तक अप्रत्यक्ष स्तर से अस्पष्ट हो गया।

संबंधित मुद्दे