2017-05-31 3 views
8

मैं सवाल "Does a const reference prolong the life of a temporary?", जिसमें कहा गया है करने के लिए this answer पाया है:क्या इस कॉन्स संदर्भ में इसका जीवन संरक्षित है?

केवल स्थानीयconst संदर्भ उम्र को लम्बा खींच।

मुझे डर है कि मेरा मानदंड यह जानने के लिए खरोंच नहीं है कि foo, नीचे एक स्थानीय कॉन्स्ट संदर्भ है या नहीं।

क्या const std::string& foo अस्थायी std::string के जीवनकाल को लंबे समय तक बढ़ाता है get_or पर कॉल में बनाया गया फ़ंक्शन तर्क, या क्या मेरे पास एक खतरनाक संदर्भ है?

#include <iostream> 
#include <boost/optional.hpp> 

struct Foo 
{ 
    const std::string& get_or(const std::string& def) 
    { 
     return str ? str.get() : def; 
    } 

    boost::optional<std::string> str; 
}; 

int main() 
{ 
    Foo f; 
    const std::string& foo = f.get_or("hello world"); 

    std::cout << foo << '\n'; 
} 
+2

स्वीकार किए जाते हैं जवाब आपके द्वारा संदर्भित प्रश्न (जो मानक उद्धृत करता है) स्पष्ट रूप से दो मामलों का कहना है जहां यह काम नहीं करता है। आपका उदाहरण दूसरा मामला है: फ़ंक्शन कॉल में संदर्भ पैरामीटर के लिए अस्थायी बाध्य। तो उत्तर नहीं है। –

उत्तर

4

const& उस स्थिति में जीवनकाल का विस्तार नहीं करेगा। example here पर विचार करें जो अस्थायी बनाता है और फिर इसे प्रिंट करने का प्रयास करता है: यह आपके कोड के समान संरचनाओं का उपयोग कर रहा है, लेकिन मैंने इसे ऑब्जेक्ट निर्माण और विनाश को उपयोगकर्ता के लिए अधिक स्पष्ट बनाने के लिए बदल दिया है।

#include <iostream> 

struct reporting { 
    reporting() { std::cout << "Constructed" << std::endl;} 
    ~reporting() { std::cout << "Destructed" << std::endl;} 
    reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;} 
    reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;} 
    reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;} 
    reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;} 

    void print() const {std::cout << "Printing." << std::endl;} 
}; 

const reporting& get_or(const reporting& def) 
{ 
    return def; 
} 

int main() 
{ 
    const reporting& foo = get_or(reporting{}); 

    foo.print(); 
    return 0; 
} 

आउटपुट:

Constructed 
Destructed 
printing. 

नोट कैसे वस्तु से पहले printing. प्रदर्शित किया जाता है नष्ट हो जाता है।

आप सोच रहे होंगे कि कोड अभी भी कोई दृश्य त्रुटियों के साथ पूरा क्यों नहीं होता है: यह अपरिभाषित व्यवहार का परिणाम है। प्रश्न में वस्तु मौजूद नहीं है, लेकिन क्योंकि यह राज्य पर अपनी विधि का आह्वान करने पर निर्भर नहीं है, कार्यक्रम क्रैश नहीं होता है। अन्य, अधिक जटिल उदाहरणों में कोई गारंटी नहीं लेनी चाहिए कि यह बिना किसी दुर्घटनाग्रस्त या अन्य, अप्रत्याशित व्यवहार के कारण काम करेगा।

संयोग से, बातें करता है, तो अस्थायी bound directly to the const& है थोड़ा अलग हैं:

#include <iostream> 

struct reporting { 
    reporting() { std::cout << "Constructed" << std::endl;} 
    ~reporting() { std::cout << "Destructed" << std::endl;} 
    reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;} 
    reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;} 
    reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;} 
    reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;} 

    void print() const {std::cout << "printing." << std::endl;} 
}; 

const reporting& get_or(const reporting& def) 
{ 
    return def; 
} 

int main() 
{ 
    const reporting& foo = reporting{}; 

    foo.print(); 
    return 0; 
} 

आउटपुट:

Constructed 
printing. 
Destructed 

देखें कैसे वस्तु जब तक के बाद यह प्रयोग किया जाता है को नष्ट कर दिया नहीं है। इस स्थिति में, वस्तु दायरे के अंत तक जीवित रहती है।

+0

बहुत व्यापक जवाब, बहुत बहुत धन्यवाद !! –

2

आपने स्ट्रिंग को कई संदर्भों के माध्यम से पारित किया।

get_or की def पैरामीटर के लिए अस्थायी स्ट्रिंग बाध्यकारी समारोह कॉल युक्त पूर्ण अभिव्यक्ति के अंत में स्ट्रिंग के जीवनकाल का विस्तार है, लेकिन get_or के रिटर्न मान पर def बंधन और foo को get_or के रिटर्न मान बाध्यकारी जीवन भर आगे नहीं बढ़ाओ। जब आप इसे प्रिंट करने का प्रयास करते हैं तो स्ट्रिंग मर जाती है।

+0

लिंक किए गए उत्तर में, टिप्पणियों में से एक [इस GOTW] को संदर्भित करता है (https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/) जो कहता है कि एक अस्थायी वापसी मूल्य के लिए एक कॉन्स-रेफ बांधना सुरक्षित है। मेरे मामले में, तथ्य यह है कि रिटर्न वैल्यू पैरामीटर से एक अस्थायी * है * यह लागू नहीं होता है? –

+0

@SteveLorimer: मान लीजिए कि आप उस लिंक में Q1 के बारे में बात कर रहे हैं, 'f' एक' स्ट्रिंग 'देता है, संदर्भ नहीं। आपका 'get_or' एक संदर्भ देता है, और उस संदर्भ के संदर्भ को इसके संदर्भ को अधिक संदर्भों में बाध्य करके विस्तारित नहीं किया जाता है। – user2357112

+0

आह हाँ, ठीक है, धन्यवाद! –

1

प्रश्न में "अस्थायी" std::string -object get_or को const char* के पैरामीटर के साथ कॉल करते समय बनाया गया है। इस अस्थायी वस्तु का जीवनकाल get_or के अंत तक सीमित है, और तथ्य यह है कि आप इस अस्थायी के संदर्भ को वापस कर देते हैं और बाद में इसे आवंटित करते हैं, जो जीवनकाल को लंबा नहीं करता है।निम्नलिखित कोड जो एक सरल "कस्टम" स्ट्रिंग वर्ग का उपयोग करता है, देखें जो cout रों निर्माण और विनाश:

class MyString { 
public: 
    MyString (const char* str) { 
     m_str = strdup(str); 
     cout << "constructor MyString - '" << m_str << "'" << endl; 
    } 
    ~MyString() { 
     cout << "destructor MyString - '" << m_str << "'" << endl; 
     free(m_str); 
    } 
    char *m_str; 
}; 

struct Foo 
{ 
    const MyString& get_or(const MyString& def) 
    { 
     cout << "Foo::get_or with '" << def.m_str << "'" << endl; 
     return def; 
    } 
}; 

int main() 
{ 
    Foo f; 
    const MyString& foo = f.get_or("hello world"); 
    cout << "usage of foo?" << endl; 
} 

आउटपुट:

constructor MyString - 'hello world' 
Foo::get_or with 'hello world' 
destructor MyString - 'hello world' 
usage of foo? 

ध्यान दें कि इससे पहले कि आप नाशक मौका होगा कहा जाता है foo का उपयोग करें।

यदि आप अस्थायी सीधे पर संदर्भ निर्दिष्ट करते हैं तो स्थिति अलग होती है। फिर, जीवन समारोह main के अंत तक है, लेकिन यह main में और किसी भी समारोह में नहीं main बुला उपयोग किया जाएगा:

const MyString& foo2 = MyString("hello world2"); 
cout << "usage of foo..." << endl; 

तो उत्पादन होगा:

constructor MyString - 'hello world2' 
usage of foo... 
destructor MyString - 'hello world2' 
संबंधित मुद्दे