tutorial - the c++ programming language




सी++ में अस्थायी गारंटीकृत जीवनकाल? (4)

क्या सी ++ एक अस्थायी चर के जीवनकाल के लिए गारंटी प्रदान करता है जो फ़ंक्शन कॉल के भीतर बनाया गया है लेकिन पैरामीटर के रूप में उपयोग नहीं किया जाता है? यहां एक उदाहरण वर्ग है:

class StringBuffer
{
public:
    StringBuffer(std::string & str) : m_str(str)
    {
        m_buffer.push_back(0);
    }
    ~StringBuffer()
    {
        m_str = &m_buffer[0];
    }
    char * Size(int maxlength)
    {
        m_buffer.resize(maxlength + 1, 0);
        return &m_buffer[0];
    }
private:
    std::string & m_str;
    std::vector<char> m_buffer;
};

और यहां बताया गया है कि आप इसका उपयोग कैसे करेंगे:

// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);

std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);

अस्थायी स्ट्रिंगबफर ऑब्जेक्ट के विनाशक को कब बुलाया जाएगा? क्या यह:

  • GetString को कॉल करने से पहले?
  • GetString रिटर्न के बाद?
  • कंपाइलर निर्भर?

मुझे पता है कि सी ++ गारंटी देता है कि एक स्थानीय अस्थायी चर तब तक मान्य होगा जब तक इसका कोई संदर्भ न हो - क्या यह सदस्य चर के संदर्भ में मूल वस्तुओं पर लागू होता है?

धन्यवाद।


GetString रिटर्न पर कॉल के बाद।


litb का जवाब सटीक है। अस्थायी वस्तु (जिसे एक रावल्यू के रूप में भी जाना जाता है) का जीवनकाल अभिव्यक्ति से जुड़ा हुआ है और अस्थायी वस्तु के विनाशक को पूर्ण अभिव्यक्ति के अंत में बुलाया जाता है और जब स्ट्रिंगबफर पर विनाशक कहा जाता है, तो m_buffer पर विनाशक भी होगा कहा जाता है, लेकिन m_str पर विनाशक नहीं है क्योंकि यह एक संदर्भ है।

ध्यान दें कि सी ++ 0x चीजों को थोड़ा सा बदलता है क्योंकि यह रैल्यू संदर्भ जोड़ता है और अर्थशास्त्र को स्थानांतरित करता है। अनिवार्य रूप से एक रावल्यू संदर्भ पैरामीटर (&& के साथ अधिसूचित) का उपयोग करके मैं रैल्यू को फ़ंक्शन में बदल सकता हूं (इसे कॉपी करने के बजाय) और रावल्यू का जीवनकाल उस ऑब्जेक्ट से बाध्य हो सकता है, जो अभिव्यक्ति में नहीं चलता है। एमएसवीसी टीम से वास्तव में एक अच्छा ब्लॉग पोस्ट है जो इस पर बहुत विस्तार से चलता है और मैं इसे पढ़ने के लिए लोगों को प्रोत्साहित करता हूं।

रैवल्यू को स्थानांतरित करने के लिए शैक्षिक उदाहरण अस्थायी तार है और मैं एक निर्माता में असाइनमेंट दिखाऊंगा। यदि मेरे पास एक श्रेणी MyType है जिसमें एक स्ट्रिंग सदस्य चर शामिल है, तो इसे कन्स्ट्रक्टर में एक रैवल्यू के साथ प्रारंभ किया जा सकता है:

class MyType{
   const std::string m_name;
public:
   MyType(const std::string&& name):m_name(name){};
}

यह अच्छा है क्योंकि जब मैं एक अस्थायी वस्तु के साथ इस वर्ग का एक उदाहरण घोषित करता हूं:

void foo(){
    MyType instance("hello");
}

क्या होता है कि हम अस्थायी वस्तु की प्रतिलिपि बनाने और नष्ट करने से बचते हैं और "हैलो" सीधे मालिक वर्ग के सदस्य चर के अंदर रखा जाता है। यदि वस्तु 'स्ट्रिंग' से भारी वजन है तो अतिरिक्त प्रति और विनाशक कॉल महत्वपूर्ण हो सकता है।


मैंने लगभग उसी वर्ग को लिखा था:

template <class C>
class _StringBuffer
{
    typename std::basic_string<C> &m_str;
    typename std::vector<C> m_buffer;

public:
    _StringBuffer(std::basic_string<C> &str, size_t nSize)
        : m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; }

    ~_StringBuffer()
        { commit(); }

    C *get()
        { return &(m_buffer[0]); }

    operator C *()
        { return get(); }

    void commit()
    {
        if (m_buffer.size() != 0)
        {
            size_t l = std::char_traits<C>::length(get());
            m_str.assign(get(), l);    
            m_buffer.resize(0);
        }
    }

    void abort()
        { m_buffer.resize(0); }
};

template <class C>
inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize)
    { return _StringBuffer<C>(str, nSize); }

मानक से पहले प्रत्येक कंपाइलर ने इसे अलग किया। मेरा मानना ​​है कि सी ++ के लिए पुराने एनोटेटेड रेफरेंस मैनुअल ने निर्दिष्ट किया है कि अस्थायी को दायरे के अंत में साफ करना चाहिए, इसलिए कुछ कंपाइलर्स ने ऐसा किया। 2003 के उत्तरार्ध में, मैंने पाया कि सूर्य के फोर्ट सी ++ कंपाइलर पर डिफ़ॉल्ट रूप से व्यवहार मौजूद था, इसलिए स्ट्रिंगबफर काम नहीं कर पाया। लेकिन अगर कोई मौजूदा कंपाइलर अभी भी टूटा हुआ था तो मुझे आश्चर्य होगा।


स्ट्रिंगबफर गेटस्ट्रिंग के दायरे में है। इसे गेटस्ट्रिंग के दायरे के अंत में नष्ट किया जाना चाहिए (यानी जब यह लौटाता है)। साथ ही, मुझे विश्वास नहीं है कि सी ++ गारंटी देगा कि जब तक कोई संदर्भ हो, तब तक एक चर मौजूद रहेगा।

निम्नलिखित संकलन करना चाहिए:

Object* obj = new Object;
Object& ref = &(*obj);
delete obj;




c++