2013-04-15 11 views
9

के साथ सेमेन्टिक्स को ले जाएं मैं विजुअल स्टूडियो 2012 अपडेट 2 का उपयोग कर रहा हूं और मुझे यह समझने में परेशानी हो रही है कि क्यों std :: vector unique_ptr की कॉपी कन्स्ट्रक्टर का उपयोग करने का प्रयास कर रहा है। मैंने इसी तरह के मुद्दों पर ध्यान दिया है और अधिकांश स्पष्ट चालक कन्स्ट्रक्टर और/या ऑपरेटर नहीं होने से संबंधित हैं।unique_ptr

यदि मैं सदस्य चर को एक स्ट्रिंग में बदलता हूं, तो मैं सत्यापित कर सकता हूं कि चालक कन्स्ट्रक्टर कहलाता है; हालांकि, संकलन त्रुटि में unique_ptr परिणामों का उपयोग करने का प्रयास कर रहा है:

error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'

मुझे उम्मीद है कि कोई मुझे जो याद कर रहा है उसे इंगित कर सकता है, धन्यवाद!

#include <vector> 
#include <string> 
#include <memory> 

class MyObject 
{ 
public: 
    MyObject() : ptr(std::unique_ptr<int>(new int)) 
    { 
    } 

    MyObject(MyObject&& other) : ptr(std::move(other.ptr)) 
    { 
    } 

    MyObject& operator=(MyObject&& other) 
    { 
     ptr = std::move(other.ptr); 
     return *this; 
    } 

private: 
    std::unique_ptr<int> ptr; 
}; 

int main(int argc, char* argv[]) 
{ 
    std::vector<MyObject> s; 
    for (int i = 0; i < 5; ++i) 
    { 
     MyObject o; 
     s.push_back(o); 
    } 

    return 0; 
} 
+1

आप सदिश में सीधे अपने वस्तुओं के निर्माण के लिए चाहते हैं, आप भी सिर्फ 'उन्हें emplace' कर सकते हैं:' के लिए (int i = 0; i <5; ++ i) s.emplace_back(); 'उसे वीसी 11 के साथ भी काम करना चाहिए। –

उत्तर

11

push_back() फ़ंक्शन मान द्वारा अपना तर्क लेता है। इसलिए, push_back() (यदि आप एक लवल्यू पास कर रहे हैं) के तर्क को प्रतिलिपि बनाने के लिए प्रयास किया गया है, या इसे स्थानांतरित करने के लिए (यदि आप एक रावल्यू पास कर रहे हैं)।

इस मामले में, o एक lvalue है - और rvalue संदर्भ lvalues ​​करने के लिए बाध्य नहीं कर सकते - क्योंकि नामित वस्तुओं lvalues ​​ हैं। इसलिए, संकलक आपके चालक कन्स्ट्रक्टर का आह्वान नहीं कर सकता है।

s.push_back(std::move(o)); 
//   ^^^^^^^^^ 

क्या मुझे इस मामले में आश्चर्य ऐसा लगता है कि VC11 MyObject के लिए एक प्रति-निर्माता उत्पन्न है परोक्ष के रूप में यह परिभाषित करने के बिना:

आदेश में अपने वस्तु ले जाया के लिए, आप लिखने के लिए है हटाए गए (आपके द्वारा पोस्ट की गई त्रुटि से निर्णय)। यह मामला नहीं होना चाहिए, क्योंकि आपकी कक्षा एक चालक कन्स्ट्रक्टर घोषित करती है। प्रति पैरा सी ++ 11 स्टैंडर्ड की 12.8/7, वास्तव में:

If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4)

मैं निष्कर्ष निकालना होगा कि त्रुटि मिल रहा है सही है - क्योंकि तुम push_back() के लिए एक rvalue गुजर नहीं कर रहे हैं - VC11 पूरी तरह से नहीं है यहां अनुपालन।

+0

बढ़िया! मुझे इस बारे में नहीं पता था। मैं अभी भी थोड़ा उलझन में हूं कि क्यों चालक कन्स्ट्रक्टर को केवल स्ट्रिंग में unique_ptr को बदलकर बुलाया जाता है। यदि वीसी 11 एक निहित प्रति रचनाकार उत्पन्न कर रहा है, तो मैं उम्मीद करता हूं कि इसका उपयोग किया जाएगा क्योंकि मैंने std :: move का उपयोग नहीं किया था। – zYzil

+1

@zYzil: सही व्यवहार प्रतिलिपि कन्स्ट्रक्टर का आह्वान नहीं करेगा और न ही 'std :: string' के चालक कन्स्ट्रक्टर (देखें [यह लाइव उदाहरण] (http://liveworkspace.org/code/3kW04t$377)), क्योंकि 'MyObject' गैर-प्रतिलिपि योग्य है और आप इससे आगे नहीं बढ़ रहे हैं। यदि आपका कोड * बिल्कुल * मेरे उदाहरण की तरह दिखता है (लापता 'std :: move()') सहित, तो VC11 में एक बग है। –

+0

मुझे निश्चित रूप से लगता है कि वीसी 11 में एक बग है। [यह उदाहरण] (http://liveworkspace.org/code/1edTJY$3) जीसीसी 4.8 पर संकलित नहीं है।0; हालांकि, वीसी 11 पर यह चलने वाले कन्स्ट्रक्टर के कारण "सीओटर ले जाएं" को संकलित और आउटपुट करता है। आपकी सभी मदद का धन्यवाद! – zYzil

4

MyObject o; ऑब्जेक्ट होने के लिए o परिभाषित करता है। जिसका मतलब है कि यह एक एल-वैल्यू है। s.push_back(o); करना push_back() (इसमें कोई अन्य विकल्प नहीं है) के एल-मान अधिभार को आमंत्रित करता है, जो एक प्रतिलिपि बनाने का प्रयास करता है।

के बाद से अपनी कक्षा noncopyable है, तो आप कदम वेक्टर में वस्तु के लिए है:

for (int i = 0; i < 5; ++i) 
{ 
    MyObject o; 
    s.push_back(std::move(o)); 
}