2010-05-20 10 views
42

मैं unique_ptr और rvalue move philosophy के साथ उलझन में हूँ।तो क्या stl संग्रह में unique_ptr सुरक्षित रूप से उपयोग किया जा सकता है?

मान लीजिए कि हम दो संग्रह करते हैं:

std::vector<std::auto_ptr<int>> autoCollection; 
std::vector<std::unique_ptr<int>> uniqueCollection; 

अब मैं उम्मीद करेंगे विफल, वहाँ कोई कह क्या एल्गोरिथ्म आंतरिक रूप से कर रही है और हो सकता है आंतरिक धुरी प्रतियां और की तरह कर रही है, इस प्रकार फाड़ है के रूप में निम्नलिखित auto_ptr से स्वामित्व दूर:

std::sort(autoCollection.begin(), autoCollection.end()); 

मुझे यह मिलता है। और संकलक सही ढंग से इस घटना को अस्वीकार करता है।

std::sort(uniqueCollection.begin(), uniqueCollection.end()); 

और यह संकलित:

लेकिन तब मैं यह कर। और मुझे समझ में नहीं आता क्यों। मुझे नहीं लगता कि unique_ptrs की प्रतिलिपि बनाई जा सकती है। क्या इसका मतलब है कि एक पिवट मूल्य नहीं लिया जा सकता है, तो सॉर्ट कम कुशल है? या यह पिवट वास्तव में एक कदम है, जो वास्तव में auto_ptrs के संग्रह के रूप में खतरनाक है, और संकलक द्वारा अस्वीकृत किया जाना चाहिए?

मुझे लगता है कि मुझे जानकारी का कुछ महत्वपूर्ण टुकड़ा याद आ रहा है, इसलिए मैं उत्सुकता से किसी को आह की आपूर्ति करने का इंतजार कर रहा हूं! पल।

+1

दरअसल संकलक * को 'std :: vector > ऑटोकॉलेक्शन के बारे में शिकायत करनी चाहिए; क्योंकि किसी भी विवरण में COAPS (ऑटो पॉइंटर्स के कंटेनर) की अनुमति नहीं है। –

+0

वीएस -2010 का उपयोग करना। मुझे/डब्ल्यू 4 पर चेतावनी भी नहीं मिली है। – DanDan

+1

या एक चेतावनी प्राप्त करें कि auto_ptr को कम किया गया है। – DanDan

उत्तर

50

मुझे लगता है कि अधिक कलाओं से दर्शन का सवाल :)

अंतर्निहित सवाल ले जाएँ और कॉपी के बीच अंतर है क्या है। मैं तकनीकी/standardista भाषा में कूद नहीं है, चलो यह बस करते हैं:

  • कॉपी: एक और समान वस्तु
  • चाल बनाने के (या कम से कम, एक जो बराबर की तुलना करनी चाहिए): एक वस्तु लेने के लिए और इसे रखा किसी अन्य स्थान पर

जैसा कि आपने कहा था, कॉपी की अवधि में स्थानांतरित करना संभव है: एक प्रतिलिपि को नए स्थान में बनाएं और मूल को छोड़ दें। हालांकि वहां दो मुद्दे हैं। एक प्रदर्शन का है, दूसरा आरएआईआई के लिए उपयोग की जाने वाली वस्तुओं के बारे में है: दोनों में से कौन सा स्वामित्व होना चाहिए?

एक उचित ले जाएँ निर्माता 2 मुद्दों को हल करती है:

  • यह स्पष्ट है जो वस्तु स्वामित्व है:, नया एक के बाद से मूल को छोड़ दिया जाएगा
  • यह इस प्रकार की नकल करने के लिए संसाधनों की ओर इशारा किया अनावश्यक है , जो अधिक दक्षता

auto_ptr और unique_ptr इस का एक बहुत अच्छा उदाहरण है।

auto_ptr के साथ आपके पास एक खराब कॉपी है अर्थात् प्रतिलिपि: मूल और प्रति बराबर तुलना नहीं करते हैं।आप इसका उपयोग अर्थात् ले जाने के लिए इसका उपयोग कर सकते हैं लेकिन एक जोखिम है कि आप कहीं भी ऑब्जेक्ट को खो देंगे।

दूसरी तरफ, unique_ptr बिल्कुल ठीक है: यह संसाधन के एक अद्वितीय मालिक की गारंटी देता है, इस प्रकार प्रतिलिपि से बचने और अनिवार्य हटाने का मुद्दा जो पालन करेगा। और संकलन समय पर नो-कॉपी की गारंटी भी है। इसलिए, जब तक आप प्रतिलिपि बनाने की कोशिश नहीं करते हैं, तब तक यह कंटेनरों में उपयुक्त है।

typedef std::unique_ptr<int> unique_t; 
typedef std::vector<unique_t> vector_t; 

vector_t vec1;       // fine 
vector_t vec2(5, unique_t(new Foo));  // Error (Copy) 
vector_t vec3(vec1.begin(), vec1.end()); // Error (Copy) 
vector_t vec3(make_move_iterator(vec1.begin()), make_move_iterator(vec1.end())); 
    // Courtesy of sehe 

std::sort(vec1.begin(), vec1.end()); // fine, because using Move Assignment Operator 

std::copy(vec1.begin(), vec1.end(), std::back_inserter(vec2)); // Error (copy) 

तो तुम एक कंटेनर में unique_ptr (auto_ptr के विपरीत) का उपयोग कर सकते हैं, लेकिन आपरेशन के एक नंबर के लिए असंभव हो जाएगा क्योंकि वे नकल किस प्रकार का समर्थन नहीं करता शामिल है।

दुर्भाग्यवश विजुअल स्टूडियो मानक के प्रवर्तन में काफी ढीला हो सकता है और इसमें कई एक्सटेंशन भी हैं जिन्हें आपको कोड की पोर्टेबिलिटी सुनिश्चित करने के लिए अक्षम करने की आवश्यकता होगी ... मानक जांचने के लिए इसका उपयोग न करें :)

+0

धन्यवाद, महान उत्तर और उदाहरण :) – DanDan

+3

आपकी टिप्पणी में "ठीक है, क्योंकि मूव कन्स्ट्रक्टर का उपयोग करना" क्या आपका मतलब है "असाइनमेंट या 'स्वैप' ले जाएं? इसके अलावा, पूर्णता के लिए, यहां 'std :: move' और 'std :: make_move_iterator' का उपयोग करके' impossibles 'किया जा सकता है: http://coliru.stacked-crooked.com/a/6b032d70a9ed6f5c – sehe

+0

@sehe: आप हैं ठीक है, मेरा मतलब है असाइनमेंट ऑपरेटर ले जाएँ। –

11

unique_ptr एस को उनके चालक कन्स्ट्रक्टर का उपयोग करके स्थानांतरित किया जा रहा है। unique_ptr चलने योग्य है, लेकिन प्रतिलिपि बनाने योग्य नहीं है।

रैल्यू संदर्भ here पर एक अच्छा लेख है। यदि आपने अभी तक उनके बारे में नहीं पढ़ा है, या उलझन में हैं, तो देखो!

+0

हे महान लेख के लिए धन्यवाद! यह पेज 7 के आसपास थोड़ा पागल हो गया है, लेकिन मैंने बहुत कुछ सीखा। लेकिन मेरी मूल समस्या बनी हुई है। अभी तक सुरक्षित क्यों हैं, प्रतियां क्यों नहीं हैं? क्या कोई अद्वितीय_प्टर नहीं है auto_ptr की प्रतिलिपि के समान ही? यदि ऑब्जेक्ट का चाल कन्स्ट्रक्टर std :: move का उपयोग कर रहा है, यानी स्वामित्व का हस्तांतरण, क्या यह auto_ptr प्रतिलिपि का डिफ़ॉल्ट व्यवहार नहीं है? – DanDan

+1

हां, लेकिन auto_ptr C++ 0x से पहले था और स्पष्ट रूप से नहीं है कंटेनर में अनुमति दी गई है। दूसरी ओर, चूंकि unique_ptr को सुरक्षित रूप से स्थानांतरित किया जा सकता है, इसलिए आप (और संकलक) आश्वासन दे सकते हैं कि स्वामित्व का उल्लंघन नहीं किया जाता है। इसके अलावा, ध्यान रखें कि एसटीएल के सॉर्ट एल्गोरिदम को निर्दिष्ट नहीं किया गया है, और सी ++ 0x में केवल चीज़ों को स्थानांतरित करने की आवश्यकता है। हालांकि, जगह में क्विकॉर्ट करना संभव है, इसलिए कोई प्रतियां जरूरी नहीं हैं। – rlbond

7

std::sort केवल चाल संचालन और कोई प्रतिलिपि के साथ काम नहीं कर सकता, जब तक कि किसी भी समय प्रत्येक ऑब्जेक्ट की केवल एक जीवित प्रतिलिपि न हो। यह जगह पर काम करने की तुलना में कमजोर आवश्यकता है, क्योंकि सिद्धांत रूप में आप अस्थायी रूप से एक और सरणी आवंटित कर सकते हैं और सभी वस्तुओं को फिर से व्यवस्थित करते समय स्थानांतरित कर सकते हैं।

उदाहरण के लिए std::vector<std::unique_ptr<T>> इसकी क्षमता से अधिक है, यह एक बड़े वेक्टर के लिए भंडारण आवंटित करता है और फिर सभी वस्तुओं को पुराने भंडारण से नए में ले जाता है। यह एक जगह में ऑपरेशन नहीं है लेकिन यह पूरी तरह से मान्य है।

जैसा कि यह पता चला है, त्वरित-क्रम और हीप-सॉर्ट जैसे एल्गोरिदम को सॉर्ट करना वास्तव में बिना किसी कठिनाई के काम कर सकता है। क्विक-सॉर्ट का विभाजन दिनचर्या आंतरिक रूप से std :: स्वैप का उपयोग करता है, जो दोनों ऑब्जेक्ट्स के लिए एक चाल ऑपरेशन के रूप में गिना जाता है। एक पिवट का चयन करते समय, एक चाल इसे सीमा में पहले तत्व के साथ स्वैप करना है, इस तरह विभाजन समाप्त होने तक इसे कभी नहीं ले जाया जाएगा।

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

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