2014-05-17 24 views
10

में प्रतिलिपि वर्ग को अक्षम करने का सबसे संक्षिप्त तरीका मुझे उपयोगकर्ता द्वारा परिभाषित विनाशक होने पर कॉपी कन्स्ट्रक्टर की प्रतिलिपि बनाने और कॉपी असाइनमेंट ऑपरेटर के बाद से बहिष्कृत करने में समस्या है।सी ++ 11

अधिकांश पर्याप्त सरल वर्गों के लिए डिफॉल्ट-जेनरेट किए गए कन्स्ट्रक्टर, ऑपरेटर और विनाशक ठीक हैं।

  1. तुच्छ नाशक आधार वर्ग में आभासी बनाना: निम्न कारणों नाशक घोषित करने के बारे में विचार करें

    // header 
    class Base1 { public: virtual ~Base1() = default; }; 
    class Base2 { public: virtual ~Base2(); }; 
    // source 
    Base2::~Base2() = default; 
    

    सभी 4 कॉपी और ले जाने के चाहेंगे विशेष तरीकों इन मामलों में संकलक द्वारा उत्पन्न किया जा? यदि हां, तो मुझे लगता है कि यह ठीक है और Base1 या Base2 को जटिल करने की कोई आवश्यकता नहीं है। नाशक में

  2. मुद्रण डिबग संदेश:

    // header 
    class D { public: ~D(); }; 
    // source 
    D::~D() { 
    #ifdef DEBUG_THIS 
        std::cout << "D was destructed." << std::endl; 
    #endif 
    } 
    

    मुझे विश्वास है कि इस मामले में प्रतिलिपि निर्माता और असाइनमेंट ऑपरेटर उत्पन्न किया जा सकता है; लेकिन कन्स्ट्रक्टर और असाइनमेंट ऑपरेटर को स्थानांतरित नहीं करेगा। मैं D की प्रतिलिपि बनाई गई डिफ़ॉल्ट प्रति उत्पन्न करने और अक्षम करने का उपयोग करना टालना चाहता हूं। मैं D बाढ़ को 4 deleted घोषणाओं से बाढ़ से बचना चाहता हूं। केवल एक कॉपी कन्स्ट्रक्टर को अक्षम कर रहा है? क्या यह एक अच्छी शैली है?

    class X 
    { 
        X(X const &) = delete; 
        void operator=(X const &x) = delete; 
    }; 
    

    मैं का पालन नहीं करते कि तुम क्या सवाल में आभासी विनाशकर्ता के साथ के बारे में बात कर रहे हैं:

+0

मुझे बहिष्करण के बारे में आपकी बात नहीं मिलती है। क्या आप स्पष्टीकरण दे सकते हैं? – stefan

+1

मानक-सी ++ में - भूमि आप केवल एक गैर-प्रतिलिपि योग्य वर्ग, जैसे 'बूस्ट :: noncopyable' से प्राप्त कर सकते हैं। विज़ुअल सी ++ के साथ आप एक मैक्रो पर विचार कर सकते हैं जो सिललीवर्निंग से बचने के लिए निजी घोषणाएं जोड़ता है। –

+0

@stefan, * अंतर्निहित परिभाषित प्रतिलिपि निर्माता की पीढ़ी को बहिष्कृत किया गया है यदि टी में उपयोगकर्ता द्वारा परिभाषित विनाशक या उपयोगकर्ता परिभाषित प्रति असाइनमेंट ऑपरेटर है। * C++ 11 के बाद से (http://en.cppreference.com/ देखें डब्ल्यू/सीपीपी/भाषा/copy_constructor # उलझाव-defined_copy_constructor)। – vedg

उत्तर

3
  1. केवल निर्माता कॉपी और कॉपी असाइनमेंट ऑपरेटर उत्पन्न हो जाएगा जब नाशक स्पष्ट रूप से चूक जाता है। और फिर भी उनकी पीढ़ी को हटा दिया गया है। तो, क्रम आभासी नाशक और सभी डिफ़ॉल्ट तरीकों के लिए, एक निम्न लिखना चाहिए:

    struct Base 
    { 
        Base()=default; 
        virtual ~Base() = default; 
        Base(const Base&)=default; 
        Base& operator=(const Base&)=default; 
        Base(Base&&)=default; 
        Base& operator=(Base&&)=default; 
    }; 
    

    मैं निश्चित रूप से एक से अधिक तरह Base वर्ग के लिए एक मैक्रो का प्रयोग करेंगे।

  2. यदि उपयोगकर्ता द्वारा परिभाषित परिभाषित किया गया है, तो 2 विशेष विधियां अभी भी उत्पन्न हुई हैं।वहाँ अक्षम पदावनत पैदा प्रतिलिपि निर्माता के लिए निम्न तरीके हैं और असाइनमेंट ऑपरेटर कॉपी:

    • हटाने चाल निर्माता या असाइनमेंट ऑपरेटर (काफी आत्म व्याख्यात्मक लेकिन बहुत ही कम नहीं) के लिए कदम:

      Base(Base&&)=delete; // shorter than deleting assignment operator 
      
    • दोनों प्रतिलिपि निर्माता हटा सकते हैं और कॉपी असाइनमेंट ऑपरेटर:

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

    ध्यान दें कि आपको डिफ़ॉल्ट कन्स्ट्रक्टर को स्पष्ट रूप से घोषित करना होगा यदि आपको इसकी आवश्यकता है, उदा। Base()=default;

    इस उद्देश्य के लिए मैक्रो या विरासत विशेष वर्ग का भी उपयोग किया जा सकता है लेकिन मैं व्यक्तिगत रूप से अपने स्वयं के मैक्रो या बेस क्लास को लागू करने के लिए चालक को हटाने को प्राथमिकता देता हूं। क्यूटी या बूस्ट का उपयोग करते समय, मैं Q_DISABLE_COPY(Base) को क्रमशः boost::noncopyable विरासत में लेना चाहूंगा, क्योंकि वे पहले ही कार्यान्वित, व्यापक रूप से ज्ञात और पहचानने योग्य हैं।

http://accu.org/index.php/journals/1896 - इन मुद्दों के लिए विस्तृत स्पष्टीकरण और तर्क।

9

कॉपी-निर्माता और कॉपी-असाइनमेंट ऑपरेटर को हटाया जा रहा निष्क्रिय करने के लिए नकल सरल और स्पष्ट तरीका है तन । ऐसा लगता है कि आप अपने कोड को स्रोत कोड के कम वर्ण लेने के लिए एक तरीका मांग रहे हैं, लेकिन इसे देखने वाले किसी भी व्यक्ति के लिए और अधिक गुप्त हो।

यदि हटाए गए कार्यों की सूची आपको परेशान करती है, तो आप उन्हें मैक्रो के पीछे छुपा सकते हैं, मुझे लगता है।

#define NON_COPYABLE_NOR_MOVABLE(T) \ 
     T(T const &) = delete; \ 
     void operator=(T const &t) = delete; \ 
     T(T &&) = delete; 
+1

यदि आप एक कंपाइलर पर काम नहीं कर रहे हैं जो '= delete' वाक्यविन्यास का समर्थन करता है, तो मैं मैक्रो का उपयोग करने की दृढ़ता से अनुशंसा करता हूं। न केवल यह अधिक पठनीय है (एक नज़र में कोडिंग ग्रोकिंग के लिए सहायक), लेकिन यह भी * खोजने योग्य * है, इस तरह से कि निजी कार्यों की एक सूची नहीं है। –

+0

1. विरासत में प्राप्त कक्षा के लिए वर्चुअल विनाशक प्रदान करना अक्सर आवश्यक होता है।मैंने पूछा कि क्या सभी 4 डिफ़ॉल्ट कन्स्ट्रक्टर/असाइनमेंट ऑपरेटर 'बेस 1' और 'बेस 2' के लिए जेनरेट किए जाएंगे। यदि * हां *, तो उनमें से किसी को स्पष्ट रूप से घोषित या हटाने की आवश्यकता नहीं है (यदि प्रतिलिपि या चलने को अक्षम करने के लिए कोई अन्य स्थिरता कारण नहीं है)। – vedg

+0

2. क्या स्पष्ट रूप से केवल एक प्रति कन्स्ट्रक्टर को हटाया जा रहा है? या शायद स्पष्ट कन्वर्टिंग कन्स्ट्रक्टर? उत्तर और टिप्पणियों के आधार पर, मुझे डर है कि कम से कम 2 विशेष तरीकों (बॉयलरप्लेट या मैक्रो या विरासत) को स्पष्ट रूप से हटाना आवश्यक है :( – vedg

10

के साथ सी ++ 11, एक साफ रास्ता बढ़ावा में इस्तेमाल पैटर्न का पालन करने के लिए है (here देखें)

आप मूल रूप से एक आधार वर्ग जहां निर्माता कॉपी और असाइनमेंट कॉपी नष्ट हो जाती हैं बनाते हैं, और यह वारिस :

class non_copyable 
{ 
protected: 
    non_copyable() = default; 
    ~non_copyable() = default; 

    non_copyable(non_copyable const &) = delete; 
    void operator=(non_copyable const &x) = delete; 
}; 

class MyClass: public non_copyable 
{ 
... 
} 
+1

यह 'non_copyable' कक्षा आम तौर पर प्रयोग करने योग्य बनाने के लिए आपको प्रासंगिक विशेष सदस्य फ़ंक्शंस जोड़ने की आवश्यकता है अब उत्पन्न नहीं हो रहे हैं। –

+0

सच, संपादित किया गया। धन्यवाद। – quantdev

+0

मैं मानता हूं कि छोटे वर्गों की बड़ी संख्या के मामले में 'non_copyable' विरासत में होना एक अच्छा विचार है। हालांकि (मेरे प्रश्न का शीर्षक)! = (पूरा प्रश्न)। वास्तव में कई सवाल हैं, और उनमें से अधिकतर अभी भी अनुत्तरित हैं। – vedg