2013-06-21 7 views
5

जबकि this question पूछ, मैं एक अस्थायी वस्तु को स्थिरांक संदर्भ सी में मान्य है ++ सीखा के बाद टूट हो जाता है संदर्भ refnop एक नष्ट अस्थायी वस्तु को संदर्भित करता है। मुझे आश्चर्य है क्योंकि?स्थिरांक संदर्भ समारोह गुंजाइश (जीवन समय)

#include <string> 
#include <map> 

struct A 
{ 
    // data 
    std::map <std::string, std::string> m; 
    // functions 
    const A& nothing()   const { return *this; } 
    void init()      { m["aa"] = "bb"; } 
    bool operator!= (A const& a) const { return a.m != m; } 
}; 

int main() 
{ 
    A a; 
    a.init(); 

    A const& ref = A(a); 
    A const& refnop = A(a).nothing(); 

    int ret = 0; 
    if (a != ref)  ret += 2; 
    if (a != refnop) ret += 4; 

    return ret; 
} 

जीसीसी 4.1.2 और एमएसवीसी 2010 का उपयोग करके परीक्षण किया गया, यह 4 लौटाता है;

$> g++ -g refnop.cpp 
$> ./a.out ; echo $? 
4 

ref और refnop के बीच का अंतर nothing() जो वास्तव में कुछ नहीं करता है के लिए कॉल है। ऐसा लगता है कि इस कॉल के बाद, अस्थायी वस्तु नष्ट हो गई है!

मेरा प्रश्न:
क्यों refnop के मामले में, अस्थायी वस्तु के जीवन समय अपने स्थिरांक संदर्भ के रूप में ही नहीं है?

+0

सावधानी: का उपयोग कर जी ++ संस्करण 4.4 और 4.6, यह स्निपेट 0 देता है ... – olibre

उत्तर

9

अस्थायी वस्तु का जीवनकाल-विस्तार केवल एक बार किया जा सकता है, जब अस्थायी वस्तु पहले संदर्भ से बंधी हो जाती है। उसके बाद, ज्ञान जो अस्थायी वस्तु को संदर्भित करता है, वह ज्ञान समाप्त हो गया है, इसलिए आगे आजीवन एक्सटेंशन संभव नहीं हैं। ,

A const& foo(A const& bar) 
{ 
    return bar; 
} 
//... 
A const& broken = foo(A()); 

दोनों ही मामलों में अस्थायी समारोह तर्क (अंतर्निहित thisnothing() के लिए, bar करने के लिए बाध्य हो जाता है:

मामले कि आप

A const& refnop = A(a).nothing(); 

puzzling है इस मामले के समान है foo() के लिए) और फ़ंक्शन तर्क के जीवनकाल में अपना जीवनकाल 'विस्तारित' प्राप्त करता है। मैंने उद्धरणों में 'विस्तारित' रखा है, क्योंकि अस्थायी का प्राकृतिक जीवनकाल पहले से ही लंबा है, इसलिए कोई वास्तविक विस्तार नहीं होता है।

क्योंकि जीवन विस्तार संपत्ति गैर संक्रामक है, एक संदर्भ (कि एक अस्थायी वस्तु का उल्लेख करने से होता है) लौटने आगे के रूप में परिणाम है कि दोनों refnop और broken की चर्चा करते हुए अंत के साथ, अस्थायी वस्तु के जीवन का विस्तार नहीं होगा वस्तुओं जो अब मौजूद नहीं है।

1

मेरा मूल उदाहरण जटिल है।

इसलिए मैं यहां एक सरल उदाहरण पोस्ट करता हूं और मैं संबंधित ISO C++ standard पैराग्राफ प्रदान करता हूं।

Cstr 4 
Cstr 5 
Dstr 5 
Cstr 6 
Dstr 6 
a4 = 4 
a5 = 0 
a6 = 0 
Dstr 4 

आप देख सकते हैं, अस्थायी a5 और a6 द्वारा संदर्भित वस्तुओं पर विलुप्त कर रहे हैं:

यह सरल उदाहरण भी coliru.stacked-crooked.com/

#include <iostream> 

struct A 
{ 
    A(int i) { std::cout<<"Cstr "<< i<<'\n'; p = new int(i); } 
~A()  { std::cout<<"Dstr "<<*p<<'\n'; delete p;  } 

    const A& thiz() const { return *this; } 

    int *p; 
}; 

const A& constref(const A& a) 
{ 
    return a; 
} 

int main() 
{ 
    const A& a4 = A(4); 
    const A& a5 = A(5).thiz(); 
    const A& a6 = constref(A(6)); 

    std::cout << "a4 = "<< *a4.p <<'\n'; 
    std::cout << "a5 = "<< *a5.p <<'\n'; 
    std::cout << "a6 = "<< *a6.p <<'\n'; 
} 

उत्पादन कमांड लाइन g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out के प्रयोग पर उपलब्ध है कार्यों का अंत thiz और constref क्रमशः।

यह §12.2 अस्थायी वस्तुओं, जहां बोल्ड हिस्सा इस मामले में लागू होता है के एक उद्धरण है:

दूसरा संदर्भ जब एक संदर्भ के लिए एक अस्थायी करने के लिए बाध्य किया जाता है। अस्थायी करने के लिए जो संदर्भ बाध्य है या अस्थायी है कि एक subobject की पूरी वस्तु को जो संदर्भ संदर्भ के जीवनकाल को छोड़कर के लिए बनी ही है:

  • एक अस्थायी एक संदर्भ सदस्य के लिए बाध्य एक निर्माता के सीटीओआर-प्रारंभकर्ता (12.6.2) में तब तक जारी रहता है जब तक कि निर्माता बाहर निकलता न हो।
  • फ़ंक्शन कॉल में एक संदर्भ पैरामीटर के लिए अस्थायी बाध्य (5.2.2) कॉल युक्त पूर्ण अभिव्यक्ति को पूरा होने तक जारी रहता है।
  • में लौटाए गए मूल्य के अस्थायी बाध्यता का जीवनकाल एक फ़ंक्शन रिटर्न स्टेटमेंट (6.6.3) विस्तारित नहीं किया गया है; अस्थायी वापसी विवरण में पूर्ण अभिव्यक्ति के अंत में नष्ट हो गया है। एक नए प्रारंभकर्ता (5.3.4) में एक संदर्भ के लिए
  • एक अस्थायी बाध्य पूर्ण अभिव्यक्ति नए प्रारंभकर्ता युक्त के पूरा होने तक बनी हुई है।

यह एक अधिक पूर्ण उदाहरण है:

#include <iostream> 

struct A 
{ 
    A()   { std::cout<<"Cstr 9\n";   p = new int(v = 9);  } 
    A(int i) { std::cout<<"Cstr "<<i<<'\n'; p = new int(v = i);  } 
    A(const A&o){ std::cout<<"Copy "<<o.v<<'\n'; p = new int(v = 10+o.v); } 
    ~A()   { std::cout<<"Del "<<v<<' '<<*p<<'\n'; *p = 88; delete p; } 

    const A& thiz() const { return *this; } 

    int *p; 
    int v; 
}; 

const A& constref(const A& a) 
{ 
    return a; 
} 

std::ostream& operator<<(std::ostream& os, const A& a) 
{ 
    os <<"{ *p="<< *a.p <<" , v="<< a.v <<" }\n"; 
    return os; 
} 

int main() 
{ 
    std::cout << "---const A a1 = A(1)"    "\n"; 
        const A a1 = A(1); 
    std::cout << "---const A a2 = A(2).thiz()"   "\n"; 
        const A a2 = A(2).thiz(); 
    std::cout << "---const A a3 = constref(A(3))" "\n"; 
        const A a3 = constref(A(3)); 
    std::cout << "---const A& a4 = A(4)"    "\n"; 
        const A& a4 = A(4); 
    std::cout << "---const A& a5 = A(5).thiz()"   "\n"; 
        const A& a5 = A(5).thiz(); 
    std::cout << "---const A& a6 = constref(A(6))" "\n"; 
        const A& a6 = constref(A(6)); 

    std::cout << "a1 = "<< a1; 
    std::cout << "a2 = "<< a2; 
    std::cout << "a3 = "<< a3; 
    std::cout << "a4 = "<< a4; 
    std::cout << "a5 = "<< a5; 
    std::cout << "a6 = "<< a6; 
} 

और इसी उत्पादन एक ही g++ कमांड लाइन का उपयोग कर:

---const A a1 = A(1) 
Cstr 1 
---const A a2 = A(2).thiz() 
Cstr 2 
Copy 2 
Del 2 2 
---const A a3 = constref(A(3)) 
Cstr 3 
Copy 3 
Del 3 3 
---const A& a4 = A(4) 
Cstr 4 
---const A& a5 = A(5).thiz() 
Cstr 5 
Del 5 5 
---const A& a6 = constref(A(6)) 
Cstr 6 
Del 6 6 
a1 = { *p=1 , v=1 } 
a2 = { *p=12 , v=12 } 
a3 = { *p=13 , v=13 } 
a4 = { *p=4 , v=4 } 
a5 = { *p=0 , v=5 } 
a6 = { *p=0 , v=6 } 
Del 4 4 
Del 13 13 
Del 12 12 
Del 1 1 
संबंधित मुद्दे