2011-04-05 14 views
9

मैं अब निम्नलिखित प्रस्ताव से लड़ रहा हूं, और मैं कानूनी और कम से कम इसके लिए नैतिक तर्क और इसके लिए जानना चाहता हूं।आरवीओ/एनआरवीओ और सार्वजनिक अपरिभाषित प्रतिलिपि निर्माता

हम क्या था:

#include <vector> 

class T; 

class C 
{ 
public: 
    C() { } 
    ~C() { /*something non-trivial: say, calls delete for all elements in v*/ } 
    // a lot of member functions that modify C 
    // a lot of member functions that don't modify C 
private: 
    C(C const &); 
    C& operator=(C const&); 
private: 
    std::vector< T* > v; 
}; 

void init(C& c) { } // cannot be moved inside C 

// ... 
int main() 
{ 
    // bad: two-phase initialization exposed to the clients 
    C c; 
    init(c); 

    // bad: here follows a lot of code that only wants read-only access to c 
    //  but c cannot be declared const 
} 

क्या प्रस्तावित किया गया है:

#include <vector> 

class T; 

class C 
{ 
public: 
    C() { } 
    ~C() { /*calls delete for all elements in v*/ } 

    // MADE PUBLIC 
    C(C const &); // <-- NOT DEFINED 

    // a lot of member functions that modify C 
    // a lot of member functions that don't modify C 
private: 
    C& operator=(C const&); 
private: 
    vector< T* > v; 
}; 

C init() // for whatever reason object CANNOT be allocated in free memory 
{ 
    C c; 
    // init c 
    return c; 
} 

// ... 
int main() 
{ 
    C const & c = init(); 
} 

यह संकलित करता है तथा लिंक (और काम करता है) हाल ही में जी का उपयोग कर ++ (जो केवल लक्षित संकलक है) दोनों 4.1.2 और 4.4.5 - (एन) आरवीओ की वजह से कॉपी-कन्स्ट्रक्टर कभी नहीं कहा जाता है; विनाशक केवल मुख्य() के अंत में बुलाया जाता है।

यह दावा किया जाता है कि तकनीक पूरी तरह से ठीक है, क्योंकि कॉपी-कन्स्ट्रक्टर का गलत इस्तेमाल नहीं किया जा सकता है (अगर इसे कभी भी जेनरेट किया गया है तो यह लिंकर त्रुटि होगी), और इसे सार्वजनिक करने के बारे में शिकायत करने के लिए संकलक को रोकता है निजी एक

यह वास्तव में मेरे लिए ऐसी चाल का उपयोग करने के लिए वास्तव में गलत लगता है, जो मुझे सी ++ भावना के विपरीत लगता है और शब्द की बुरी भावना में हैक की तरह दिखता है।

मेरी भावनाएं पर्याप्त तर्क नहीं है, इसलिए मैं अब तकनीकीताओं की तलाश में हूं।

कृपया पोस्ट न करें पाठ्यपुस्तक सी ++ यहां सामान:

  • मैं की "तीन के नियम" के बारे में पता कर रहा हूँ और 12.8/15 और पवित्र स्टैंडर्ड के 12.2 के माध्यम से पढ़ा है;
  • मैं न तो vector<shared_ptr<T> > और न ही ptr_vector<T> का उपयोग कर सकता हूं;
  • मैं C को मुफ्त मेमोरी में आवंटित नहीं कर सकता और इसे init से C* के माध्यम से वापस कर सकता हूं।

धन्यवाद।

+1

मुझे लगता है कि हिल निर्माण आपके लिए एक संभावना नहीं है? –

+0

@ कोनराड रुडॉल्फ: दुर्भाग्य से नहीं (g ++ 4.1.2 उन कंपाइलरों में से एक है जिन्हें हमें समर्थन देना चाहिए, इस प्रकार कोई 0x विशेषताएं नहीं)। –

+5

"इसे सार्वजनिक बनाने के बारे में शिकायत करने के लिए बेवकूफ संकलक को रोकता है।" - बेवकूफ संकलक नहीं। मानक की आवश्यकता है कि कॉपी कन्स्ट्रक्टर पहुंच योग्य है भले ही प्रतिलिपि बनाई गई हो, क्योंकि प्रतिलिपि elision वैकल्पिक है। इसलिए यदि इसे निजी होने की अनुमति दी गई तो एक प्रोग्राम जो किसी त्रुटि से बचने के लिए elision पर निर्भर करता है, वैसे भी सख्ती से अनुरूप नहीं होगा, और इस मामले में मानक को निदान की आवश्यकता होती है। संकलक पोर्टेबल कोड लिखने में आपकी मदद कर रहा है, स्वीकार्य रूप से आपकी इच्छाओं के विरुद्ध ;-) –

उत्तर

10

यह संकलित करता है तथा लिंक (और काम करता है) हाल ही में जी ++ (जो केवल लक्षित संकलक है) दोनों 4.1.2 और 4.4.5 का उपयोग कर - (एन) की वजह से RVO कॉपी-निर्माता नहीं है बुलाया; विनाशक केवल मुख्य() के अंत में बुलाया जाता है।

हालांकि यह जीसीसी के साथ काम कर सकता है, लेकिन आपके कोड में वास्तव में अपरिभाषित व्यवहार है क्योंकि यह परिभाषित नहीं किया गया एक फ़ंक्शन संदर्भित करता है। ऐसे मामले में, आपका कार्यक्रम खराब गठित है; कोई निदान की आवश्यकता नहीं है। जिसका अर्थ है कि जीसीसी नियम उल्लंघन को अनदेखा कर सकता है, लेकिन अन्य कंपाइलर्स इसका निदान कर सकते हैं या अजीब कुछ और कर सकते हैं।

तो उन आधार पर, मैं इस तरह से अस्वीकार कर दूंगा।

मेरी भावनाएं पर्याप्त तर्क नहीं है, इसलिए मैं अब तकनीकीताओं की तलाश में हूं।

आप यहां अर्थशास्त्र को स्थानांतरित करना चाहते हैं। यह स्पष्ट होने के बारे में क्या?

class T; 
class C; 

struct CMover { 
    C *c; 
private: 
    CMover(C *c):c(c) { } 
    friend CMover move(C &c); 
}; 

class C { 
public: 
    C() { } 
    ~C() { /*calls delete for all elements in v*/ } 

    C(CMover cmove) { 
     swap(v, cmove.c->v); 
    } 

    inline operator CMover(); 

    // a lot of member functions that modify C 
    // a lot of member functions that don't modify C 
private: 
    C& operator=(C const&); // not copy assignable 
    C(C &); // not lvalue copy-constructible 

private: 
    vector< T* > v; 
}; 

CMover move(C &c) { return CMover(&c); } 
C::operator CMover() { return move(*this); } 
अब

आप कह सकते हैं

C init() // for whatever reason object CANNOT be allocated in free memory 
{ 
    C c; 
    return move(c); 
} 

int main() { 
    C const c(init()); 
} 
+0

क्या आप कृपया मुझे बता सकते हैं कि सी ++ 03 कहां अपरिभाषित कार्यों को संदर्भित करता है? सैमसंगिक्स को स्थानांतरित करने के संबंध में, हम यह नहीं चाहते कि * इस विशेष मामले में बुरी तरह से * मेरा प्रश्न इस प्रस्ताव के बारे में अधिक है कि इस प्रस्ताव को स्वीकार या प्रतिबंधित क्यों किया जाना चाहिए। –

+4

@Alex 3.2p3, प्रस्ताव को अस्वीकार कर दिया जाना चाहिए क्योंकि यह पोर्टेबल काम नहीं करता है। मैं आपका प्रश्न समझता हूं, लेकिन मुझे लगा कि मैं यह भी बताउंगा कि मैं आपके प्रश्न का उत्तर देने के अलावा इसे कैसे हल करूंगा। –

+0

धन्यवाद, 3.2/2 + 3.2/3 स्पष्ट रूप से दिखाता है कि वह यूबी है। इसके अलावा हमने अभी पता लगाया है कि एमएसवीसी ++ 2008 और 2010 (जो समर्थित नहीं हैं * अब *, लेकिन आप कभी नहीं जानते) इस कोड को अस्वीकार कर दें। –

0

स्पष्ट उत्तर यह है कि संकलक प्रतिलिपि बनाने के लिए कोई दायित्व नहीं है, खासकर यदि अनुकूलन अक्षम है (हालांकि g ++ अभी भी ऑप्टिमाइज़ेशन के बिना भी प्रतिलिपि बनाता है)। इस प्रकार, आप पोर्टेबिलिटी को प्रतिबंधित कर रहे हैं।

अधिकतर यदि यह किसी विशेष कंपाइलर पर संकलित होता है तो यह अपेक्षा के अनुसार कार्य करेगा।

मुझे पता है कि आप क्या कर सकते हैं पर मनमाने ढंग से कृत्रिम/कृत्रिम प्रतिबंधों का एक टन है, लेकिन क्या आप C के लिए प्रॉक्सी धारक का उपयोग करने में सक्षम हैं?

class C 
{ 
private: 
    C() { } 
    ~C() { /*calls delete for all elements in v*/ } 

    // ... 
    friend class C_Proxy; 
}; 

class C_Proxy 
{ 
public: 
    C_Proxy() : c_() { init(c_); } 

    // Or create a public const& attribute to point to this. 
    const C& get_C() const { return c_; } 

private: 
    C c_; 
}; 
0

यह कुछ आप अभ्यस्त अकेले (उर्फ "लेकिन यह संकलित करता है तथा हमारे संकलक पर काम करता है!"), तो हो सकता है तकनीकी कारणों पर लोगों के सिर से बाहर निकलने की तरह दिखता है एक अवधारणात्मक सरल दृष्टिकोण एक अच्छा विचार हो सकता है?

आपकी चिंता constness है ...

C c; 
init(c); 

// bad: here follows a lot of code that only wants read-only access to c 
//  but c cannot be declared const 

बनाम

C const & c = init(); 

सरल (के रूप में: कोई हैक्स और प्रॉक्सी सामान) की आवश्यकता समाधान हो सकता है:

C c_mutable_object; 
init(c_mutable_object); 
C const& c = c_mutable_object; 

// ... lots of code with read-only access to c 
संबंधित मुद्दे