2015-03-13 5 views
6

मैं विधि, अपरिवर्तित, और सी ++ में प्रतिलिपि के बिना पैरामीटर कैसे लौटा सकता हूं?मैं एक विधि, अपरिवर्तित, और सी ++ में एक प्रति के बिना एक अपरिवर्तनीय पैरामीटर कैसे वापस कर सकता हूं?

// This is more or less the desired signature from the caller's point of view 
SomeImmutableObject ManipulateIfNecessary(SomeImmutableObject const& existingObject) 
{ 
    // Do some work… 
    // ... 

    if (manipulationIsNeccessary) 
    { 
     // Return a new object with new data etc (preferably without another copy)... 
     return SomeImmutableObject(...); 
    } 
    else 
    { 
     // Return the original object intact (but with no further copies!)... 
     return existingObject; 
    } 
} 

एक उदाहरण सी # के String.Trim तरीका है। सी # स्ट्रिंग्स अपरिवर्तनीय हैं और यदि ट्रिम को कोई काम नहीं करना है, तो मौजूदा स्ट्रिंग का संदर्भ वापस कर दिया जाता है, अन्यथा छंटनी की गई सामग्री के साथ एक नई स्ट्रिंग ऑब्जेक्ट लौटा दी जाती है।

मैं उपरोक्त विधि हस्ताक्षर के करीब कुछ दिए गए सी ++ में इस अर्थपूर्ण की नकल कैसे करूं?

+0

"अन्यथा एक नई स्ट्रिंग ऑब्जेक्ट ..." तो फिर आप एक प्रतिलिपि से क्यों बचना चाहते हैं? –

+0

संदर्भ द्वारा पास सी ++ में इसी तरह से काम करता है, सी ++ में समान कोड का उपयोग करने में क्या गलत है? –

+1

यदि आप एनआरवीओ के बारे में बात कर रहे हैं, तो मुझे नहीं लगता कि यह यहां लागू है। –

उत्तर

2

आपकी ऑब्जेक्ट को काम करने के लिए एक संदर्भ प्रकार होना चाहिए। के तार के लिए एक खिलौना उदाहरण देता हूँ:

class RefString { 
public: 
    RefString() : ref(new std::string()) { } 
    RefString(const std::string& str) : ref(new std::string(str)) { } 

    RefString trim_trailing_newline() { 
     if (ref->back() == '\n') { 
      return RefString(ref->substr(0, ref->size()-1)); 
     } 

     return *this; 
    } 

    size_t size() { return ref->size(); } 

private: 
    std::shared_ptr<std::string> ref; 
}; 

int main(int argc, char** argv) { 
    RefString s("test\n"); 
    std::cout << s.size() << "\n"; 
    std::cout << s.trim_trailing_newline().size() << "\n"; 
    return 0; 
} 
+0

आह, दिलचस्प है क्योंकि मैं वास्तव में प्रदान किए गए उदाहरण के साथ ट्रिम को कार्यान्वित करना चाहता हूं :) मुझे यह देखने के लिए प्रोफाइल करना होगा कि क्या जीतता है, अगर कोई है, तो मेरे सामान्य इनपुट के साथ shared_ptr मार्ग का उपयोग करके प्राप्त किया जाता है आकार। –

+0

हालांकि यह समाधान उन स्ट्रिंग्स के लिए स्पष्ट जीत साबित हुआ, जिनके लिए वास्तविक कार्य को ट्रिम करने की आवश्यकता नहीं थी, दुर्भाग्यवश उन लोगों के लिए बहुत भारी था जो साझा_प्टर उपयोग के लिए अतिरिक्त स्मृति आवंटन के कारण करते थे। महान पैटर्न हालांकि मैं भविष्य के लिए चारों ओर रख रहा हूँ! –

1

एक उचित विकल्प के लिए एक तरह से इस का समर्थन करता है SomeImmutableObject लागू करने के लिए है -, आंतरिक रूप से तार्किक राज्य के लिए एक संदर्भ बार गणना स्मार्ट सूचक के रूप में है, जबकि बाहर से यह मूल्य अर्थ विज्ञान प्रदान कर सकता है । (यह थ्रेडेड कोड से उपयोग को मुश्किल कर सकते हैं - आप पर कॉपी-ऑन-राइट (गाय) और क्यों यह std::string लागू करने के लिए अलोकप्रिय बन पढ़ सकते हैं।)

यदि आप किसी मौजूदा SomeImmutableObject कार्यान्वयन आप कर सकते हैं के साथ फंस रहे हैं बदल नहीं है, और आप इसे संदर्भ-गणना वाले स्मार्ट-पॉइंटर के साथ लपेट नहीं सकते हैं, फिर विकल्प सीमित हो जाते हैं।

: एक दूसरे समारोह में -

यह रूप में स्वच्छ कॉलर उपयोग प्रदान नहीं करता है, लेकिन आप manipulationIsNeccessary एक फोन करने वाले से सुलभ समारोह कर सकता है, तो फोन करने वाले कोड "नए डेटा से नई वस्तु" कहते है

SomeImmutableObject obj; const SomeImmutableObject& o = manipulationIsNecessary(obj) ? newObjectWithNewData(obj) : obj; ...use o... 

newObjectWithNewData होने से एक अलग कार्य हो, आपको रिटर्न वैल्यू ऑप्टिमाइज़ेशन लात मारना चाहिए (हालांकि यह आपके कंपाइलर/सेटिंग्स के साथ जांचना हमेशा अच्छा होता है)।

+0

शायद मैंने इस विषय से बहुत अधिक विवरण छुपाए जाने की उम्मीद में छुपाया है, लेकिन इसके बजाय एक और रास्ता नीचे ले जाता है :) असल में मैं एक कुशल std :: basic_string दोनों ट्रिम और स्प्लिट के लिए विधि को लागू करने की कोशिश कर रहा हूं - दोनों में इन मामलों में एक अलग 'चेक' विधि अधिक नहीं होगी क्योंकि यह विधि बाद में नई ऑब्जेक्ट बनाने के लिए आवश्यक डेटा तैयार करेगी - इसलिए उन्हें एक साथ बंद रखना होगा। –

1

आप हमेशा स्थिरांक कुछ ImmutableObject & वापस कर सकते हैं। ध्यान दें कि किसी ऑब्जेक्ट को परिणाम देने से प्रतिलिपि एक प्रतिलिपि होगी।

SomeImmutableObject x = ManipulateIfNecessary(y); // will invoke a copy-ctor 

असली चाल कार्यान्वयन होगी। जब पहली "अगर" खंड का असर होता है तो आप संभावित रूप से अस्थायी चर (करने के लिए बुरी चीज) के संदर्भ को वापस कर देंगे। नव निर्मित वस्तु को गतिशील रूप से आवंटित करना होगा।

सब, मुझे नहीं लगता कि यह कुछ स्मार्ट मेमोरी प्रबंधन w/o आसानी से संभव है।

+0

* "नव निर्मित ऑब्जेक्ट को गतिशील रूप से आवंटित करना होगा।" * - और वहां रगड़ है ... आप ऑब्जेक्ट रिकॉर्ड के अंदर एक ध्वज प्राप्त कर सकते हैं कि इसे इतना आवंटित किया गया था, और केवल 'delete_self()' फ़ंक्शन है जो केवल ऐसा करता है अगर वह झंडा सेट है, लेकिन यह क्लाइंट उपयोग में सभी बदसूरत बदसूरत और नाजुक है .... –

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