2013-03-03 6 views
9

को रोकने के लिए, मैं अब एक सदिश में इसका इस्तेमाल कर सकते हैं:क्यों हटाया जा रहा है चाल निर्माता कारण वेक्टर अगर मैं एक कक्षा में कदम निर्माता रोकना काम कर

class Foo 
{ 
    public: 
     Foo(int i) : i_(i) {} 
     Foo(Foo&&) = delete; 

     int i_; 
}; 

int main() 
{ 
    std::vector<Foo> foo; 
    foo.push_back(Foo(1)); 
} 

क्यों है ऐसा?

+1

क्योंकि push_back MoveInsertable होने के लिए प्रकार की आवश्यकता है। बस डॉक्स पढ़ें: http://en.cppreference.com/w/cpp/container/vector/push_back –

उत्तर

34

सारांश

चाल सदस्यों को न हटाएं।


मान लिया जाये कि आपके संकलक पूरी तरह से सी ++ 11 अनुरूप है, तो स्पष्ट रूप से इस कदम निर्माता हटाने पर परोक्ष निम्नलिखित घोषणा करेंगे है:

Foo(const Foo&) = delete; 
Foo& operator=(const Foo&) = delete; 

कि अगर है कि आप एक कदम निर्माता की घोषणा (या असाइनमेंट ऑपरेटर ले जाएं), और प्रतिलिपि सदस्यों की घोषणा न करें, उन्हें पूरी तरह से हटाए जाने के रूप में घोषित किया जाता है।

class Foo 
{ 
    public: 
     Foo(int i) : i_(i) {} 
     Foo(Foo&&) = delete; 
     Foo(const Foo&) = delete;    // implicitly declared 
     Foo& operator=(const Foo&) = delete; // implicitly declared 

     int i_; 
}; 

अब vector<Foo>::push_back(Foo(1)) की आवश्यकता है कि FooMoveConstructible हो: तो अपना पूरा वर्ग फू के रूप में अगर है। MoveConstructible एक सुलभ चालक कन्स्ट्रक्टर द्वारा या यहां तक ​​कि एक सुलभ प्रतिलिपि द्वारा भी संतुष्ट हो सकता है। लेकिन Foo न तो है। आपको ठीक करने के लिए:

class Foo 
{ 
    public: 
     Foo(int i) : i_(i) {} 
     Foo(const Foo&) = default; 
     Foo& operator=(const Foo&) = default; 

     int i_; 
}; 

आईई। प्रतिलिपि सदस्यों को डिफ़ॉल्ट करें और हटाए गए चालक सदस्य को हटा दें।

आम तौर पर चाल सदस्यों को स्पष्ट रूप से हटाने का अच्छा विचार नहीं है। यदि आप कक्षा को प्रतिलिपि बनाना चाहते हैं लेकिन "चलने योग्य" नहीं हैं, तो बस ठीक उसी तरह घोषित करें जैसे आप सी ++ 03 में करेंगे: अपनी प्रतिलिपि सदस्यों को घोषित/परिभाषित करें। आप कॉपी सदस्यों को = default के साथ संकलक-जेनरेट करने दे सकते हैं, और यह अभी भी उपयोगकर्ता-घोषणा के रूप में गिना जाता है। और चाल सदस्यों की घोषणा मत करो। उन सदस्यों को ले जाएं जो मौजूद नहीं हैं हटाए गए स्थान सदस्यों के समान नहीं हैं।

हटाए गए कदम सदस्यों का मतलब है कि आप एक रेवल्यू से Foo की एक प्रति नहीं बना सकते हैं, भले ही कॉपी कन्स्ट्रक्टर ऐसा करने के लिए ठीक काम करता। यह शायद ही वांछित इरादा है।

भले ही आप अपनी कक्षा को कॉपी करने योग्य और न ही चलने योग्य बनाना चाहते हैं, फिर भी प्रतिलिपि सदस्यों को हटाना बेहतर है और आगे बढ़ने वाले सदस्यों को छोड़ दें (जिसका अर्थ है कि वे मौजूद नहीं होंगे)। यदि आप कभी भी कोड (स्वयं सहित) की समीक्षा कर रहे हैं, और हटाए गए कदम सदस्यों को देखते हैं, तो वे लगभग निश्चित रूप से गलत हैं, या सबसे अच्छे और भ्रामक हैं।

कुछ दिन कोई हटाए गए कदम सदस्यों के लिए एक अच्छा उपयोग केस के साथ आएगा। लेकिन यह एक दुर्लभ उपयोग मामला होगा। यदि आप कोड में ऐसा पैटर्न देखते हैं, तो आपको कोड लेखक को बहुत अच्छी स्पष्टीकरण की उम्मीद करनी चाहिए। अन्यथा, हटाए गए कदम सदस्यों को केवल गलत होने की संभावना है (सर्वोत्तम अनावश्यक पर)। लेकिन उज्ज्वल तरफ यह त्रुटि रन समय के बजाए संकलित समय पर दिखाई देगी (जैसा कि आपके उदाहरण में है)।

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

enter image description here

= default और = delete गिनती के रूप में उपयोगकर्ता के घोषित

Click here यदि आप पूर्ण स्लाइड डेक देखना चाहते हैं।

+1

यह [यहां अपना उत्तर] को इसमें से कुछ सामग्री कॉपी करने के लिए सहायक हो सकता है (http://stackoverflow.com/ ए/26492184/1708801) मुझे वास्तव में यह अधिक जानकारी, +1 की तलाश में मिला। –

+0

@ShafikYaghmour: धन्यवाद, यह अच्छी सलाह है, किया गया। –

+0

यदि मैं एक वर्ग को प्रतिलिपि बनाना चाहता हूं लेकिन चलने योग्य नहीं हूं, तो क्या यह वास्तव में प्रतिलिपि सदस्यों को पूरी तरह से उत्पन्न करने के लिए पर्याप्त है? यह [उत्तर] (http://stackoverflow.com/a/4944131) कहता है कि चालक सदस्यों को तब तक जेनरेट नहीं किया जाएगा जब तक कोई उपयोगकर्ता चालक सदस्य या विनाशक घोषित नहीं करता है। – guini

0

आप कहते हैं:

मैं अब एक सदिश में इसका इस्तेमाल कर सकते हैं:

हालांकि, सी ++ 11, एक सदिश में उपयोग के लिए आवश्यकताओं को कम से कम कर रहे हैं के बाद से; इसके बजाय, प्रत्येक वेक्टर ऑपरेशन की अपनी आवश्यकताएं होती हैं। तो, वास्तव में आप एक वेक्टर में Foo उपयोग कर सकते हैं, लेकिन आप आपरेशनों है कि वस्तु की आवश्यकता होती है की कोई संभावना नहीं ले जाया गया या कॉपी करने के लिए तक ही सीमित हैं।

उदाहरण के लिए आप लिख सकते हैं:

std::vector<Foo> w(5); 
w.pop_back(); 

और आप भी w[0].some_member_function(); और इतने पर कॉल कर सकते हैं।

हालांकि आप निम्न में से कोई, कारण जिस तरह से आप Foo परिभाषित करने के लिए नहीं लिख सकता:

std::vector<Foo> w = { 1, 2, 3 }; // Requires moving elements out of initializer_list 
w.resize(5);  // Resize may mean reallocation which may require elements to be moved to new location 
w.push_back(5);  // ditto 
w.erase(w.begin()); // Erasing an element may require other elements to move to fill its place 
w[0] = 1;   // operator= is implicitly deleted as described in Howard's answer (but you could explicitly default it to make this work) 

आप Foo copyable, लेकिन चल नहीं हो करना चाहते हैं - और किसी भी कदम परिदृश्यों पीछे हटना है एक प्रति का उपयोग करने के लिए - तो ऐसा करने का एकमात्र तरीका किसी भी चालक-निर्माता को घोषित नहीं करना है; और एक नाशक, कॉपी-निर्माता की घोषणा के द्वारा संकलक उत्पन्न चाल-निर्माता की बल निषेध, और/या कॉपी-असाइनमेंट ऑपरेटर के रूप में हॉवर्ड की तालिका में दिखाया गया।

इस का एक उदाहरण के लिए हावर्ड के जवाब में पिछले कोड नमूना देखें।

स्पष्ट है इस कदम निर्माता, सभी हॉवर्ड की तालिका में दिखाया गया के लिए वास्तव में कई अलग अलग संभावित स्थितियां होती हैं:

  1. परिभाषित किया जाता है के रूप में नष्ट कर दिया, और के रूप में नष्ट उपयोगकर्ता परिभाषित
  2. परिभाषित किया जाता है, और नहीं उपयोगकर्ता से परिभाषित (यह तब होता है जब एक सदस्य चल नहीं है)
  3. चूक और उपयोगकर्ता परिभाषित
  4. चूक और नहीं उपयोगकर्ता परिभाषित
  5. उपयोगकर्ता-प्रदान की (यानी उपयोगकर्ता परिभाषित और न डिफ़ॉल्ट टेड है और न ही नष्ट कर दिया)

घोषित नहीं मामलों 1, 3, 4, ऊपर 5, चाल निर्माता अधिभार संकल्प द्वारा पाया जाता है। मामलों में 2 और 6 यह अधिभार संकल्प द्वारा नहीं मिला है; और push_back(Foo(1)); जैसे प्रतिलिपि/चाल परिदृश्य एक कॉपी कन्स्ट्रक्टर (यदि कोई हो) पर वापस आ जाएगा।

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