2011-04-18 13 views
20

कभी-कभी सी ++ कक्षा में एक कॉपी कन्स्ट्रक्टर को प्रतिबंधित करना आवश्यक है ताकि कक्षा "गैर-प्रतिलिपि" हो। बेशक, operator= एक ही समय में निषिद्ध होना चाहिए।सी ++ में एक कॉपी कन्स्ट्रक्टर को प्रतिबंधित करने का सबसे विश्वसनीय तरीका क्या है?

अब तक मैंने ऐसा करने के दो तरीके देखे हैं। मार्ग 1 निजी प्रणाली की घोषणा और यह कोई कार्यान्वयन दे रहा है:

class Class { 
//useful stuff, then 
private: 
    Class(const Class&); //not implemented anywhere 
    void operator=(const Class&); //not implemented anywhere 
}; 

रास्ता 2 निजी प्रणाली की घोषणा और यह दे रहा है "खाली" कार्यान्वयन:

class Class { 
//useful stuff, then 
private: 
    Class(const Class&) {} 
    void operator=(const Class&) {} 
}; 

IMO पहले एक बेहतर है - यहां तक ​​कि अगर कुछ अप्रत्याशित कारण है जो कॉपी क्लास को उसी वर्ग सदस्य फ़ंक्शन से बुलाया जाता है तो बाद में एक लिंकर त्रुटि होगी। दूसरे मामले में इस परिदृश्य को रनटाइम तक अनजान छोड़ा जाएगा।

क्या पहली विधि में कोई गंभीर कमी है? अगर कोई और क्यों बेहतर तरीका है?

+4

http://www.boost.org/doc/libs/1_46_1/boost/noncopyable.hpp – dgnorton

उत्तर

16

पहली विधि यह है कि बूस्ट इसे हल करता है (source code), जहां तक ​​मुझे पता है, कोई कमी नहीं है। वास्तव में, लिंकर त्रुटियां उस विधि का बड़ा लाभ हैं। आप चाहते हैं कि त्रुटियां लिंक समय पर हों, न कि जब आपका ग्राहक आपका कोड निष्पादित कर रहा हो और अचानक क्रैश हो जाए।

यदि आप बूस्ट का उपयोग कर रहे हैं, तो आप स्वयं को कुछ टाइपिंग सहेज सकते हैं। यह आपका पहला उदाहरण के रूप में ही कार्य करता है:

#include <boost/utility.hpp> 

class Class : boost::noncopyable { 
// Stuff here 
} 
+7

हालांकि यह "बूस्ट कैसे हल करता है" हो सकता है, फिर भी बेस क्लास में इसे हल करने और इसे स्वयं अपनी कक्षा में करने के बीच एक महत्वपूर्ण अंतर है, जिसमें बेस-क्लास दृष्टिकोण बहुत अधिक आत्म-दस्तावेज है, किसी को रोकना बाद में इसे कक्षा में लापरवाही से जोड़कर, सोच रहा था कि यह गलती से अनुपूरक था। –

+0

यह अभी भी एक अच्छा परिदृश्य होगा, क्योंकि इससे आपको वास्तविक नुकसान होने से पहले किसी को पकड़ने की अनुमति मिलती है। बेशक, आप जूनियर को यह जानने की उम्मीद नहीं कर सकते हैं, लेकिन उन्हें बिना किसी समीक्षा के ऐसे परिवर्तन नहीं करना चाहिए। – MSalters

+0

@ टोनी: मैं भी बूस्ट विकल्प को पसंद करता हूं (या एक और कस्टम क्लास जब बूस्ट का उपयोग नहीं किया जा सकता है)। यह समझना आसान है, और अधिक पठनीय, और त्रुटि संदेश थोड़ा बेहतर हैं। –

25

पहले एक बेहतर है

और भी बेहतर C++0x 'delete' keyword है:

class Class { 
// useful stuff, then 
public: 
    Class(const Class&) = delete; 
    void operator=(const Class&) = delete; 
}; 
+6

@sehe: 'delete' के साथ इसे निजी बनाने का कोई कारण नहीं है। वास्तव में, यह सार्वजनिक इंटरफ़ेस में दिखाई देने से बेहतर, उपयोगकर्ता के अनुसार लगता है। –

+0

अच्छा बिंदु। – sehe

+0

अद्यतन @Matthieu इस संदर्भ में 'हटाएं' का उपयोग सी ++ 11 है; यदि आपको किसी भी पुराने कंपाइलर्स को लक्षित करना है, और यहां तक ​​कि हाल ही में बहुत से लोग, तो आप इसका उपयोग नहीं कर सकते हैं। –

7

तुम हमेशा boost::noncopyable से विरासत कर सकते हैं।

अन्यथा मैंने कभी नहीं देखा है कि नंबर 1 की तुलना में कोई कारण संख्या 2 बेहतर है क्योंकि यह आपको किसी ऑब्जेक्ट को क्लास या क्लास विधियों के भीतर "प्रतिलिपि बनाने" की अनुमति देगा, भले ही यह वास्तव में ऑब्जेक्ट की एक वास्तविक प्रतिलिपि नहीं बनाएगा ।

2

अपना पहला दृष्टिकोण में कोई खामी नहीं है, मैं बनाने के लिए "गैर copyable" वर्ग का उपयोग किया गया है कि ..

3

अन्य उत्तर कुछ और पता चलता है कि , और वास्तव में प्रश्न का उत्तर देने का प्रयास नहीं करता है, इसलिए मेरा प्रयास यहां है:

तो कौन सा दृष्टिकोण बेहतर है? यह इस बात पर निर्भर करता है कि आप को पर प्रतिलिपि कैसे प्रतिबंधित करते हैं?

आप दोस्तों और सदस्य-कार्यों की इजाजत दी कॉपी करने के लिए, जबकि कॉपी करने से दूसरों को (केवल गैर दोस्त वर्गों और कार्यों) को रोकने के लिए चाहते हैं, तो दूसरा दृष्टिकोण जाने का रास्ता है।

यदि आप प्रतिलिपि बनाने से सभी (दोस्तों, गैर-मित्र, सदस्य-कार्य) को रोकना चाहते हैं, तो पहला दृष्टिकोण केवल सही समाधान है।

ध्यान दें कि दूसरा दृष्टिकोण मित्रों और सदस्य-कार्यों को कॉपी करने से रोकता नहीं है (यानी, कॉपी-फ़ंक्शंस को कॉल करने से)

1. यदि आप उन्हें दूसरे मामले में सही ढंग से परिभाषित नहीं करते हैं, तो कॉपी अपेक्षित के रूप में काम नहीं करेगी, लेकिन यह पूरी तरह से एक अलग बात है। लेकिन मुद्दा यह है कि दूसरा मामला कॉपी-फ़ंक्शंस को कॉल करने से नहीं रोकता है। कंपाइलर कोई त्रुटि संदेश उत्पन्न नहीं करेगा।

1

व्यक्तिगत रूप से मुझे लगता है कि आपने अपने स्वयं के प्रश्न का उत्तर दिया है, और पहले दृष्टिकोण का उपयोग करना चाहिए।

यदि आप इसे कॉपी करने योग्य नहीं चाहते हैं, जैसा कि आपने कहा है कि यह एक लिंकर त्रुटि फेंक देगा। हालांकि यदि आप दूसरे दृष्टिकोण का उपयोग करते हैं और आप प्रतिलिपि द्वारा कॉपी कन्स्ट्रक्टर का उपयोग कर समाप्त करते हैं, तो यह संकलित होगा और यह चलाएगा; और आपको बिल्कुल कोई संकेत नहीं मिलेगा कि असंगतता तब तक आई जब तक आप एक डीबगर खोलने के लिए नहीं आते। या जैसा कि नेहे ने कहा, यदि आप आधुनिक कंपाइलर का उपयोग कर सकते हैं, तो C++ 11 '' delete 'नोटेशन का उपयोग करें।

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