एक नवनिर्मित वस्तु को कब्जे में अपरिभाषित व्यवहार द्वारा कैप्चर कर रहा है


11

निम्नलिखित (विपरीत उदाहरण) ठीक है या यह अपरिभाषित व्यवहार है:

// undefined behavior?
const auto& c = SomeClass{};

// use c in code later
const auto& v = c.GetSomeVariable();

जवाबों:


12

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

एक अस्थायी वस्तु का जीवनकाल एक अंतराल अंतराल के संदर्भ में या एक अंतराल संदर्भ (सी ++ 11 के बाद से) के लिए बाध्य करके बढ़ाया जा सकता है, विवरण के लिए संदर्भ आरंभीकरण देखें।

जब भी किसी संदर्भ को अस्थायी या उसके अधीन करने के लिए बाध्य किया जाता है, तो अस्थायी का जीवनकाल निम्नलिखित अपवादों के साथ संदर्भ के जीवनकाल से मेल खाने के लिए बढ़ाया जाता है :

  • रिटर्न स्टेटमेंट में किसी फ़ंक्शन के रिटर्न मान के लिए एक अस्थायी सीमा को विस्तारित नहीं किया जाता है: यह रिटर्न एक्सप्रेशन के अंत में तुरंत नष्ट हो जाता है। इस तरह के फ़ंक्शन हमेशा एक झूलने वाला संदर्भ देता है।
  • कंस्ट्रक्टर इनिशियलाइज़र सूची में एक संदर्भ सदस्य के लिए एक अस्थायी बाध्य केवल तब तक बनी रहती है जब तक कि कंस्ट्रक्टर बाहर नहीं निकलता है, जब तक कि ऑब्जेक्ट मौजूद नहीं है। (नोट: इस तरह की इनिशियलाइज़ेशन DR 1696 के रूप में बीमार है)।
  • एक फंक्शन कॉल में एक रेफरेंस पैरामीटर के लिए एक अस्थायी बाध्य, फंक्शन एक्सप्रेशन वाले पूर्ण एक्सप्रेशन के अंत तक मौजूद होता है: यदि फंक्शन एक रेफरेंस देता है, जो फुल एक्सप्रेशन को आउटलाइव करता है, तो यह एक झूलने वाला रेफरेंस बन जाता है।
  • एक नए-अभिव्यक्ति में उपयोग किए गए इनिशियलाइज़र में एक संदर्भ के लिए एक अस्थायी बाध्य उस नए-अभिव्यक्ति वाले पूर्ण अभिव्यक्ति के अंत तक मौजूद है, जब तक कि प्रारंभिक ऑब्जेक्ट के रूप में नहीं। यदि आरंभिक वस्तु पूर्ण अभिव्यक्ति को रेखांकित करती है, तो इसका संदर्भ सदस्य एक झूलने वाला संदर्भ बन जाता है।
  • सूची-आरंभीकरण सिंटैक्स (ब्रेसिज़) का उपयोग करते हुए प्रत्यक्ष-आरंभीकरण सिंटैक्स (कोष्ठक) का उपयोग करते हुए एक प्रारंभिक प्रारंभिक के संदर्भ तत्व में एक संदर्भ के लिए एक अस्थायी बाध्य, इनिशियलाइज़र युक्त पूर्ण अभिव्यक्ति के अंत तक मौजूद है। struct A { int&& r; }; A a1{7}; // OK, lifetime is extended A a2(7); // well-formed, but dangling reference

सामान्य तौर पर, अस्थायी के जीवनकाल को "इसे पास करके" आगे नहीं बढ़ाया जा सकता है: एक दूसरा संदर्भ, जिस संदर्भ से अस्थायी बाध्य था, उसके जीवनकाल को प्रभावित नहीं करता है।

के रूप में @Konrad रूडोल्फ ने बताया (और ऊपर के अंतिम पैराग्राफ देखें):

"यदि c.GetSomeVariable()किसी स्थानीय वस्तु के संदर्भ में या एक संदर्भ में यह किसी वस्तु के जीवनकाल का विस्तार करता है, तो आजीवन विस्तार किक नहीं करता है"


1
आपको उस उद्धरण के स्रोत का हवाला देना चाहिए।
को ऑर्बिट

@LightnessRaceswithMonica किया। मुझे एक बेहतर पाठ की तलाश थी।
विस्मयादिबोधक

2
यह रेखांकित करना अच्छा होगा कि यह केवल मूल्यों के लिए सही है । अगर c.GetSomeVariable()रिटर्न एक संदर्भ एक स्थानीय वस्तु के लिए या एक संदर्भ यह अपने आप में किसी वस्तु के जीवनकाल का विस्तार है कि, जीवन विस्तार करता है नहीं में लात।
कोनराड रूडोल्फ

@KonradRudolph धन्यवाद! मैंने अपवाद भी जोड़ा।
विस्मयादिबोधक

4

यहां कोई मुद्दा नहीं होना चाहिए, आजीवन विस्तार के लिए धन्यवाद । नवनिर्मित वस्तु तब तक जीवित रहेगी जब तक संदर्भ दायरे से बाहर नहीं जाता।


3

हां यह पूरी तरह से सुरक्षित है: एक constसंदर्भ के लिए बंधन अस्थायी के जीवनकाल का विस्तार उस संदर्भ के दायरे तक करता है।

ध्यान दें कि व्यवहार हालांकि सकर्मक नहीं है । उदाहरण के लिए, साथ

const auto& cc = []{
    const auto& c = SomeClass{};
    return c;
}();

cc dangles।


2

यह सुरक्षित है।

[class.temporary]/5: तीन संदर्भ हैं जिनमें पूर्ण अभिव्यक्ति के अंत की तुलना में एक अलग बिंदु पर अस्थायी रूप से नष्ट हो जाते हैं । [..]

[class.temporary]/6: तीसरा संदर्भ तब है जब एक संदर्भ एक अस्थायी वस्तु से बंधा हो। वह अस्थायी वस्तु जिसका संदर्भ बद्ध है या वह अस्थायी वस्तु जो किसी उप-विषय की पूरी वस्तु है, जिसके संदर्भ में संदर्भ बंधा हुआ है, संदर्भ के आजीवन के लिए बनी रहती है, यदि वह संदर्भ जिसके संदर्भ में सीमा है, निम्न में से एक के माध्यम से प्राप्त किया गया था : [यहाँ बहुत सारी चीजें]


1

यह इस विशिष्ट मामले में सुरक्षित है। ध्यान दें कि सभी अस्थायी नक्षत्रों को कब्जे में लेने के लिए सुरक्षित नहीं है ... उदाहरण के लिए

#include <stdio.h>

struct Foo {
    int member;

    Foo() : member(0) {
        printf("Constructor\n");
    }

    ~Foo() {
        printf("Destructor\n");
    }

    const Foo& method() const {
        return *this;
    }
};

int main() {
    {
        const Foo& x = Foo{};        // safe
        printf("here!\n");
    }
    {
        const int& y = Foo{}.member; // safe too (special rule for this)
        printf("here (2)!\n");
    }
    {
        const Foo& z = Foo{}.method(); // NOT safe
        printf("here (3)!\n");
    }
    return 0;
}

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

Constructor
here!
Destructor
Constructor
here (2)!
Destructor
Constructor
Destructor
here (3)!
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.