2017-08-08 15 views
49

अंदर निम्नलिखित कोड ठीक संकलित:C++ {* इस} घुंघराले ब्रेसिज़

g++ -std=c++11 test.cpp -Wall -Wextra -Wfatal-errors && ./a.out 

हालांकि, अगर मैं {*this} से घुंघराले ब्रेसिज़ हटाने और बजाय *this उपयोग करते हैं, मैं त्रुटि के साथ सामना करेंगे:

error: use of deleted function ‘Obj::Position::Position(Obj::Position&&)’

{*this} और *this के बीच क्या अंतर है?

class Obj 
{ 
    template<bool> friend class Position; 

    double data; 
public: 
    class Position 
    { 
     const Obj& ref; 
    public: 
     inline Position(const Obj& ref): ref(ref){} 
     inline Position(Position const &) = delete; 
     inline Position(Position &&) = delete; 
    }; 
    inline Obj(){} 
    inline Obj(const double &data): data(data){} 
    inline auto get_pos() const-> Position{return {*this};} /* <--- here */ 
    inline auto get_pos()-> Position{return {*this};} 
}; 

int main() 
{ 
    return 0; 
} 

उत्तर

13

दोनों के बीच का अंतर वास्तव में काफी सूक्ष्म है। सी ++ 11 सुविधा सूची प्रारंभ (भी कभी कभी कहा जाता है ब्रेस प्रारंभ) की शुरुआत की:

सी ++ 11 से पहले, जब आप डिफ़ॉल्ट-निर्माण करने के लिए और प्रकार Obj की o वस्तु और एक Position po से निर्माण चाहते हैं

Obj o();   // mistake: declares a function o returning an Obj 
Obj::Position p(o); // error: no constructor takes a function 
012:, आप

Obj o;    // default construct o 
Obj::Position p(o); // construct p using Position(Obj const&) 

लिखना पड़ा शुरुआती (विशेष रूप से एक जावा पृष्ठभूमि के साथ) के लिए एक सामान्य त्रुटि यह लिखने की कोशिश करने के लिए था

पहली पंक्ति function घोषित करती है, और दूसरा एक कन्स्ट्रक्टर का उपयोग करके Position बनाने का प्रयास करता है जो फ़ंक्शन पॉइंटर को इसके तर्क के रूप में लेता है। आदेश एक समान प्रारंभकर्ता वाक्य रचना करने के लिए, सी ++ 11 शुरू की सूची प्रारंभ:

Obj oo{};    // new in C++11: default construct o of type Obj 
Obj::Position p1(oo); // possible before (and after) C++11 
Obj::Position p2{oo}; // new in C++11: construct p2 using Position(Obj const&) 

इस नई वाक्य रचना भी return -statements में काम करता है, और यह अपने प्रश्न का जवाब की ओर जाता है: return {*this}; और return *this; के बीच का अंतर कि पूर्व, *this से सीधे वापसी मान initializes जबकि बाद पहले धर्मान्तरित *this एक अस्थायी Position वस्तु के लिए और फिर परोक्ष रूप से यह अस्थायी से वापसी मान initializes, जो विफल रहता है, क्योंकि दोनों copy- और ले जाने-निर्माता है स्पष्ट रूप से हटा दिया गया है।

जैसा कि पिछले पोस्टर ने नोट किया है, अधिकांश कंपाइलर इन अस्थायी वस्तुओं को बढ़ाते हैं क्योंकि वे वास्तव में कुछ भी उपयोगी नहीं हैं; लेकिन यह केवल तभी संभव है जब उनका सिद्धांत सिद्धांत में उपयोग किया जा सके क्योंकि या तो एक प्रतिलिपि या चालक कन्स्ट्रक्टर उपलब्ध है। क्योंकि इससे बहुत भ्रम पैदा होता है (मुझे अपने रिटर्न स्टेटमेंट के आसपास ब्रेसिज़ की आवश्यकता क्यों है? क्या संकलक प्रतिलिपि बनाने के लिए जा रहा है या नहीं?), सी ++ 17 इन अनावश्यक अस्थायी लोगों से दूर है, और वापसी मूल्य सीधे शुरू करता है दोनों मामलों में (return {*this}; और return *this)।

आप सी ++ 17 का समर्थन करने वाले एक कंपाइलर का उपयोग करके इसे आजमा सकते हैं। क्लैंग 4.0 या जीसीसी 7.1 में, आप --std=c++1z पास कर सकते हैं, और आपके कोड को ब्रेसिज़ के साथ और बिना ठीक संकलित करना चाहिए।

38

घुंघराले ब्रेसिज़ मौजूद हैं, आप copy-list-initializing रहे वापसी मान, कोई कॉपी/कदम निर्माता शामिल है। Position(const Obj&) कन्स्ट्रक्टर का उपयोग कर return value is constructed in-place

ध्यान दें कि कोड भी घुंघराले ब्रेसिज़ के साथ संकलित करने के लिए विफल हो जाएगा यदि आप Position(const Obj&) निर्माता explicit क्योंकि कॉपी-सूची-प्रारंभ स्पष्ट कंस्ट्रक्टर्स कहा जा करने की अनुमति नहीं बनाया है।

यदि आप घुंघराले ब्रेसिज़ को छोड़ देते हैं, तो अर्थात् एक अस्थायी Position ऑब्जेक्ट फ़ंक्शन के भीतर बनाया गया है, और वापसी मूल्य उस अस्थायी से बनाया गया है। व्यावहारिक रूप से, अधिकांश कार्यान्वयन कदम निर्माण को बढ़ाएंगे, लेकिन इसके लिए अभी भी एक व्यवहार्य चालक कन्स्ट्रक्टर मौजूद होना आवश्यक है, जो यहां मामला नहीं है क्योंकि इसे स्पष्ट रूप से हटा दिया गया है। यही कारण है कि आपका कोड ब्रेसिज़ के बिना संकलित नहीं होगा।

एक सी ++ 17 कंपाइलर का उपयोग करके, आपका कोड guaranteed copy-elision की वजह से घुंघराले ब्रेसिज़ के बिना भी संकलित होगा।

+0

मुझे आश्चर्य है कि मैं स्थिति (Obj :: स्थिति &) 'की बजाय त्रुटि में' स्थिति (Obj :: स्थिति &&) ''क्यों देखता हूं, जब मैं ब्रेसिज़ को छोड़ देता हूं। यह विपरीत की तरह दिखता है। – ar2015

+0

@ ar2015 क्या आपका मतलब है कि आप त्रुटि संदेश में 'स्थिति (स्थिति स्थिरांक ') के बजाय' स्थिति (स्थिति &&) 'क्यों देखते हैं? ऐसा इसलिए है क्योंकि आपके पास एक मूल्य 'स्थिति' ऑब्जेक्ट है जिसमें से वापसी मूल्य आरंभ करने के लिए और चालक कन्स्ट्रक्टर एक बेहतर मिलान है। यदि आप 'इनलाइन स्थिति (स्थिति &&) = हटाएं;' पंक्ति पर टिप्पणी करते हैं, तो त्रुटि संदेश में कॉपी कन्स्ट्रक्टर होगा। – Praetorian

+0

यह मूल रूप से "मैंने इसे प्रतिबंधित कर दिया है, तो मैंने ऐसा करने की कोशिश की" यदि वास्तव में इसकी आवश्यकता है – Swift

13

यह एक अच्छा है! ऐसा इसलिए है क्योंकि return {...} का अर्थ है "सूची प्रारंभकर्ता के साथ शुरू किए गए फ़ंक्शन के रिटर्न प्रकार का ऑब्जेक्ट वापस करें ..."।

सूची initializers यहां और विवरण में वर्णित हैं:

inline Position(const Obj& ref): ref(ref){} 

जबकि *this की कोशिश करता उपयोग करके Position को Obj& परिवर्तित स्पष्ट रूप से नष्ट कर दिया:

http://en.cppreference.com/w/cpp/language/list%20initialization

तो, अंतर यह है कि {*this} कॉल यह है असाइनमेंट ऑपरेटर (प्री सी ++ 11, उन्हें private बनाना होगा, और आपको और भी भ्रमित होना होगा

int main() 
{ 
    Obj o1; 
    cout<<"get position"<<'\n'; 
    Obj::Position pos= o1.get_pos(); 


    cout.flush(); 
    return 0; 
} 

यह दोनों में (जीसीसी/MinGW) संकलन नहीं करता है: त्रुटि संदेश यदि सूची initializers उपलब्ध होगा ...):

inline Position(Position const &) = delete; 
inline Position(Position &&) = delete; 
-2

स्पष्ट रूप से, अपने वर्ग का उपयोग करने और मुख्य निम्नलिखित() मामलों (-std = C++ 14), घुंघराले ब्रेसिज़ के साथ या बिना और यह अनुपस्थित स्थिति (स्थिति & &) के बारे में शिकायत करता है जो कि हटाया गया है। यह उचित है क्योंकि ऐसा लगता है कि दोनों मामलों में अस्थायी वापसी वस्तु का निर्माण किया जाता है, जिसे तब गंतव्य स्थानांतरित किया जाना है। जो चालक कन्स्ट्रक्टर हटा दिया गया है असंभव है। इसके विपरीत, -std = C++ 17 ध्वज का उपयोग करके यह दोनों मामलों (घुंघराले ब्रेसिज़ के साथ या बिना) में संकलित करता है, सबसे अधिक संभावना है कि हम सी ++ 17 की गारंटीकृत वापसी-मूल्य अनुकूलन को मार रहे हैं। उम्मीद है कि यह मदद करता है।

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