क्या कॉन्स्ट सन्दर्भ द्वारा डिफ़ॉल्ट तर्क का मान वापस करना ठीक है?


26

क्या नीचे दिए उदाहरणों में कॉन्स्ट सन्दर्भ द्वारा डिफ़ॉल्ट तर्क के मान को वापस करना ठीक है:

https://coliru.stacked-crooked.com/a/ff76e060a007723b

#include <string>

const std::string& foo(const std::string& s = std::string(""))
{
    return s;
}

int main()
{
    const std::string& s1 = foo();
    std::string s2 = foo();

    const std::string& s3 = foo("s");
    std::string s4 = foo("s");
}

3
सरल परीक्षण: std::stringअपने स्वयं के वर्ग के साथ बदलें ताकि आप निर्माण और विनाश को ट्रैक कर सकें।
user4581301

1
@ user4581301 यदि अनुक्रम सही है तो यह साबित नहीं होगा कि निर्माण ठीक है।
पीटर -

6
@ user4581301 "जब मैंने इसे आज़माया तो यह काम करता दिखाई दिया" अपरिभाषित व्यवहार के बारे में सबसे बुरी बात है
हेरोइजेंट

यह ध्यान दिया जाना चाहिए कि प्रश्न इसकी शब्दावलियों में भ्रामक है। आप कॉन्स्टिट्यूशन द्वारा डिफॉल्ट लॉजिक की वैल्यू नहीं लौटा रहे हैं, लेकिन आप एक कॉन्स्ट रेफरेंस को एक कॉन्स्ट रेफरेंस (... डिफॉल्ट लॉजिक के लिए) लौटा रहे हैं।
डेमन

2
@ हेरॉयट 100% कथन से सहमत है, लेकिन उस संदर्भ का नहीं, जिसका आप उपयोग कर रहे हैं। जिस तरह से मैंने इसे पढ़ा है वह इस सवाल का समाधान करता है कि "वस्तु का जीवनकाल कब खत्म होता है?" जब विध्वंसक कहा जाता है, तो यह करना एक अच्छा तरीका है। एक स्वचालित चर के लिए विध्वंसक को समय पर सही कहा जाना चाहिए या आपको बड़ी समस्याएं मिली हैं।
user4581301

जवाबों:


18

आपके कोड में, दोनों s1और s3संदर्भ लटक रहे हैं। s2और s4ठीक हैं।

पहली कॉल में, std::stringडिफ़ॉल्ट तर्क से बनाई गई अस्थायी खाली ऑब्जेक्ट कॉल वाले अभिव्यक्ति के संदर्भ में बनाई जाएगी। इसलिए, यह परिभाषा के अंत में मर जाएगा s1, जो s1झूलना छोड़ देता है ।

दूसरी कॉल में, अस्थायी std::stringऑब्जेक्ट का उपयोग आरंभ करने के लिए किया जाता है s2, फिर यह मर जाता है।

तीसरी कॉल में, स्ट्रिंग शाब्दिक "s"का उपयोग एक अस्थायी std::stringवस्तु बनाने के लिए किया जाता है और वह भी झूलते हुए s3, की परिभाषा के अंत में मर जाता है s3

चौथी कॉल में, std::stringमूल्य वाली अस्थायी वस्तु "s"का उपयोग आरंभ करने के लिए किया जाता है s4और फिर उसकी मृत्यु हो जाती है।

देखें C ++ 17 [class.temporary] /6.1

फ़ंक्शन कॉल (8.2.2) में संदर्भ पैरामीटर के लिए बाध्य एक अस्थायी ऑब्जेक्ट तब तक बनी रहती है जब तक कि पूर्ण-अभिव्यक्ति कॉल युक्त न हो।


1
उत्तर का दिलचस्प हिस्सा यह दावा है कि कॉलर के संदर्भ में डिफ़ॉल्ट तर्क बनाया जाएगा। लगता है कि यह गिलौम के मानक उद्धरण द्वारा समर्थित है।
पीटर -

2
@ पीटर-रेनस्टेमोनिका देखें [expr.call] / 4, "... कॉलिंग फ़ंक्शन के संदर्भ में प्रत्येक पैरामीटर का प्रारंभ और विनाश होता है ..."
ब्रायन

8

यह सुरक्षित नहीं है :

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


तो क्या आपको लगता std::string s2 = foo();है कि वैध है (आखिरकार, कोई संदर्भ स्पष्ट रूप से पारित नहीं हुआ है)?
पीटर -

1
@ पीटर-रेनस्टोमोनिका कि एक सुरक्षित है क्योंकि नई वस्तु का निर्माण किया जाएगा। मेरा जवाब जीवन भर के विस्तार के बारे में है। अन्य दो उत्तर पहले से ही सब कुछ कवर करते हैं। मैं अपने में नहीं दोहराता।
विस्मृति

5

यह इस बात पर निर्भर करता है कि आप बाद में स्ट्रिंग के साथ क्या करते हैं।

यदि आपका प्रश्न मेरा कोड सही है? तो हाँ है।

से [dcl.fct.default] / 2

[ उदाहरण : घोषणा

void point(int = 3, int = 4);

एक फ़ंक्शन को घोषित करता है जिसे शून्य, एक या दो प्रकार के int के साथ बुलाया जा सकता है। इसे इनमें से किसी भी तरीके से बुलाया जा सकता है:

point(1,2);  point(1);  point();

अंतिम दो कॉल क्रमशः point(1,4)और point(3,4), के बराबर हैं। - अंतिम उदाहरण ]

तो आपका कोड प्रभावी रूप से इसके बराबर है:

const std::string& s1 = foo(std::string(""));
std::string s2 = foo(std::string(""));

आपका सभी कोड सही है, लेकिन इनमें से किसी भी मामले में संदर्भ आजीवन विस्तार नहीं है, क्योंकि वापसी प्रकार एक संदर्भ है।

चूंकि आप किसी फ़ंक्शन को अस्थायी रूप से कॉल करते हैं, इसलिए जीवन भर लौटे स्ट्रिंग स्टेटमेंट का विस्तार नहीं करेंगे।

const std::string& s1 = foo(std::string("")); // okay

s1; // not okay, s1 is dead. s1 is the temporary.

आपके उदाहरण के साथ s2ठीक है जब से आप satement के अंत से पहले अस्थायी से कॉपी (या स्थानांतरित) करते हैं। s3से एक ही समस्या है s1

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