2015-12-09 7 views
5

मुझे पता है कि आरवीओ अधिकतर लागू होता है लेकिन क्या मैं उस पर भरोसा कर सकता हूं? मेरे पास एक ऐसा फ़ंक्शन है जो क्लास फ्लैगकॉन्टेनर का ऑब्जेक्ट बनाता है।रिटर्न मूल्य अनुकूलन और विनाशक कॉल

class FlagContainer { 
public: 
    ~FlagContainer() { 
     someItem->flag = true; 
    } 
private: 
    Item * someItem; 
} 

public FlagContainer createFlagContainer() { 
    return FlagContainer(); 
} 

कॉलर कंटेनर का उपयोग करने के बाद, ध्वज सेट किया जाना चाहिए। तो मैं इसे विनाशक के साथ कर सकता हूं।

{ 
    FlagContainer container = createFlagContainer(); 
    // do something with container 
} 

जब दायरे से बाहर, विनाशक को बुलाया जाएगा। लेकिन क्या मैं यह सुनिश्चित कर सकता हूं कि विनाशक को कभी भी CreateFlagContainer में नहीं बुलाया जाएगा? क्या इसे प्राप्त करने का कोई तरीका है?

मैं एवीआर जीसीसी 4.7.0 कंपाइलर का उपयोग करूंगा।

+1

"मुझे पता है कि आरवीओ ..." क्षमा करें, * क्या * आपको वास्तव में पता है? "अधिकांशतः लागू" का अर्थ क्या है, और "अधिकांशतः लागू" पर भरोसा करने का क्या अर्थ होगा? – juanchopanza

+0

आरवीओ ** ** ** लागू करने की आवश्यकता नहीं है। यह मानक द्वारा अस्तित्व में रहने की अनुमति है। C12+ 17 के बाद से इस मामले में –

+0

आरवीओ की आवश्यकता है। एमएसवीसी, जीसीसी, क्लैंग हमेशा इस परिदृश्य में आरवीओ प्रदर्शन करेंगे ('-फनो-एलिइड-कन्स्ट्रक्टर' को छोड़कर)। – Simple

उत्तर

5

मुझे पता है कि आरवीओ अधिकतर लागू होता है लेकिन क्या मैं उस पर भरोसा कर सकता हूं?

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

क्या यह हासिल करने का कोई तरीका है?

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

std::unique_ptr (चाल निर्माणकर्ता और ऑपरेटरों कुख्यात सही पाने के लिए मुश्किल हो जाता है) बेकार अच्छी तरह से काम करता है।

#include <iostream> 
#include <memory> 
#include <cassert> 

// test type 
struct X 
{ 
    bool flag = false; 
}; 


// a custom deleter that sets a flag on the target 

struct flag_setter_impl 
{ 
    template<class X> 
    void operator()(X* px) const { 
     if (px) { 
      assert(!px->flag); 
      std::cout << "setting flag!" << std::endl; 
      px->flag = true; 
     } 
    } 
}; 

// a type of unique_ptr which does not delete, but sets a flag 
template<class X> 
using flag_setter = std::unique_ptr<X, flag_setter_impl>; 

// make a flag_stter for x 

template<class X> 
auto make_flag_setter(X& x) -> flag_setter<X> 
{ 
    return flag_setter<X>(&x, flag_setter_impl()); 
} 


// quick test 

auto main() -> int 
{ 
    using namespace std; 

    X x; 

    { 
     auto fs1 = make_flag_setter(x); 
     auto fs2 = move(fs1); 
    } 
    return 0; 
} 

लेकिन मैं अपने लक्ष्य पर एसटीएल नहीं है

फिर से 0, 3, 5

#include <iostream> 
#include <memory> 
#include <cassert> 

// test type 
struct X 
{ 
    bool flag = false; 
}; 


// a custom deleter that sets a flag on the target 

struct flag_setter_impl 
{ 
    template<class X> 
    void operator()(X* px) const { 
     if (px) { 
      assert(!px->flag); 
      std::cout << "setting flag!" << std::endl; 
      px->flag = true; 
     } 
    } 
}; 

// a type of unique_ptr which does not delete, but sets a flag 
template<class X> 
struct flag_setter 
{ 
    flag_setter(X* px) : px(px) {} 
    flag_setter(const flag_setter&) = delete; 
    flag_setter(flag_setter&& r) noexcept : px(r.px) { r.px = nullptr; } 
    flag_setter& operator=(const flag_setter& r) = delete; 
    flag_setter& operator=(flag_setter&& r) 
    { 
     flag_setter tmp(std::move(r)); 
     std::swap(tmp.px, px); 
     return *this; 
    } 
    ~flag_setter() noexcept { 
     flag_setter_impl()(px); 
    } 

private: 
    X* px; 
}; 

// make a flag_stter for x 

template<class X> 
auto make_flag_setter(X& x) -> flag_setter<X> 
{ 
    return flag_setter<X>(&x); 
} 


// quick test 

auto main() -> int 
{ 
    using namespace std; 

    X x; 

    { 
     auto fs1 = make_flag_setter(x); 
     auto fs2 = move(fs1); 
    } 
    return 0; 
} 
+0

मेरे लक्ष्य के लिए कोई एसटीएल उपलब्ध नहीं है ... :( – DreyFax

+0

@DreyFax परिणाम के रूप में उत्तर अपडेट किया गया –

1

मैं जानता हूँ कि अपने नियम भूल नहीं है कि आरवीओ ज्यादातर लागू होता है लेकिन क्या मैं उस पर भरोसा कर सकता हूं?

नहीं। कंपाइलर्स को आरवीओ लागू करने की अनुमति है, लेकिन आवश्यक नहीं है। आप केवल उस पर भरोसा कर सकते हैं, जब आपका कंपाइलर ऐसा करने का वादा करता है।

+0

मेरी माफ़ी, मैंने गलती से मेरा जवाब संपादित किया। अब फिक्स्ड। –

1

हालांकि मानक 12.8/3/p31.1 के अनुसार यह विशेष मामला कक्षा वस्तुओं की प्रतिलिपि बनाना और स्थानांतरित करना [class.copy] एक संदर्भ के रूप में प्रस्तुत करता है कि संकलक एनआरवीओ (उर्फ कॉपी एलिशन) कर सकता है, आप भरोसा नहीं कर सकते यह। एक कार्यक्रम जो इस तरह के अनुकूलन पर निर्भर करता है प्रभावी रूप से गैर पोर्टेबल है।

वस्तु मैं एक चाल निर्माता को परिभाषित करने और मैं अन्य वस्तु का सूचक शून्य होगा अंदर हैं की चाल सुनिश्चित करने के लिए है, जबकि नाशक में मैं क्रम में की जाँच करेगा सूचक है कि क्या nullptr इसके झंडे सच स्थापित करने के लिए:

class FlagContainer { 
public: 
    FlagContainer(FlagContainer&& other) : someItem(other.someItem) { 
     other.someItem = nullptr; 
    } 
    ~FlagContainer() { 
     if(someItem) someItem->flag = true; 
    } 

    Item * someItem; 
}; 

FlagContainer createFlagContainer() { 
    return FlagContainer(); 
} 

Live Demo

+0

... यदि आप दिखाते हैं तो यह एक विचार हो सकता है चालक कन्स्ट्रक्टर का कार्यान्वयन अन्य.someItem ... –

+1

"और वापसी में std :: move का उपयोग करें" यह अपने बेहतरीन पर निराशाजनक है। –

+0

कन्स्ट्रक्टर मूव सही जवाब है, लेकिन मैं खुद को ऊपर नहीं लौटा सकता 'वापसी std: : इस कदम (FlagContainer()); '। – nwp

2

कोई गारंटी नहीं है [अभी तक] कि कॉपी-इलिजन लागू किया जाता है। Guaranteed copy-elision को सी ++ 17 में शामिल करने के लिए प्रस्तावित किया गया है।चाहे कॉपी-एलिशन लागू किया गया हो, पूरी तरह से कंपाइलर के विवेकाधिकार पर है (कुछ कंप्यूटर्स के पास इसे पूरी तरह अक्षम करने का विकल्प है)।

एक संभावित दृष्टिकोण इस जरूरत से परहेज जो केवल प्रकार आप इस्तेमाल किया जा रहा है और उस प्रकार का ऑब्जेक्ट वापस जाने के लिए में रुचि रखते हैं के लिए निर्माता तर्क के रूप में इस्तेमाल किया जा सकता एक अनिवार्य रूप से व्यर्थ प्रकार का उपयोग हो सकता है:

class FlagContainerBuilder { 
    friend class FlagContainer; 
public: 
    FlagContainerBuilder(/* suitable arguments go here */); 
    // nothing goes here 
}; 

class FlagContainer { 
    // ... 
public: 
    FlagContainer(FlagContainerBuilder&& builder); 
    // as before 
}; 

FlagContainerBuilder createFlagContainer() { ... } 

इस तरह से आप को संभावित रूप से createFlagContainer() से वापस करने की आवश्यकता से बचने की आवश्यकता से बचें।

संबंधित मुद्दे