2012-07-15 15 views
14

मुझे जीसीसी से एक अजीब त्रुटि मिल रही थी और क्यों नहीं पता लगाया जा सकता है। समस्या को और स्पष्ट करने के लिए मैंने निम्नलिखित उदाहरण कोड बनाया है। असल में, एक वर्ग परिभाषित किया गया है, जिसके लिए मैं गलती से कॉल करने से रोकने के लिए अपनी प्रतिलिपि बनाने वाला और कॉपी असाइनमेंट ऑपरेटर निजी बनाता हूं।वेक्टर :: push_back कॉपी कन्स्ट्रक्टर का उपयोग करने पर जोर देता है हालांकि एक चालक कन्स्ट्रक्टर प्रदान किया जाता है

#include <vector> 
#include <cstdio> 
using std::vector; 

class branch 
{ 
public: 
    int th; 

private: 
    branch(const branch& other); 
    const branch& operator=(const branch& other); 

public: 

    branch() : th(0) {} 

    branch(branch&& other) 
    { 
    printf("called! other.th=%d\n", other.th); 
    } 

    const branch& operator=(branch&& other) 
    { 
    printf("called! other.th=%d\n", other.th); 
    return (*this); 
    } 

}; 



int main() 
{ 
    vector<branch> v; 
    branch a; 
    v.push_back(std::move(a)); 

    return 0; 
} 

मैं इस कोड को संकलित करने की उम्मीद है, लेकिन यह जीसीसी के साथ विफल रहता है। असल में जीसीसी शिकायत करता है कि "शाखा :: शाखा (कॉन्स शाखा &) निजी है", जैसा कि मुझे समझ में नहीं आना चाहिए।

असाइनमेंट ऑपरेटर, काम करता है के बाद से अगर मैं

branch a; 
branch b; 
b = a; 

के साथ) मुख्य के शरीर (की जगह यह संकलन और अपेक्षा के अनुरूप चलेंगे।

क्या यह जीसीसी का सही व्यवहार है? यदि हां, तो उपर्युक्त कोड में क्या गलत है? कोई भी सुझाव मेरे लिए सहायक है। धन्यवाद!

+0

मेरे लिए जीसीसी-4.6.1 के साथ काम करता है। –

+0

मैं जीसीसी 4.7.1-2 का उपयोग कर रहा था। मैं 4.6.1 कोशिश करूंगा। धन्यवाद! – BreakDS

+2

एन 3242 के पढ़ने के बाद, इस कोड को अनुमति दी जानी चाहिए (लेकिन यदि चालक कन्स्ट्रक्टर अपवाद फेंकता है, तो प्रोग्राम में अपरिभाषित व्यवहार होता है)। – aschepler

उत्तर

16

चालक कन्स्ट्रक्टर की घोषणा के लिए "अस्वीकरण" जोड़ने का प्रयास करें।

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

+3

यदि वह प्रतिलिपि बनाने वाले को सार्वजनिक बनाता है तो वस्तु की प्रतिलिपि बनाई जाएगी, जो स्पष्ट रूप से वह बचने की कोशिश कर रहा है। किसी भी मामले में, चालक कन्स्ट्रक्टर 'नोएक्ससेप्ट' बनाना सही समाधान है, इसलिए +1। – ildjarn

+0

आप दोनों के लिए धन्यवाद, अस्वीकरण और सार्वजनिक प्रतिलिपि निर्माता दोनों सही हैं। हालांकि, यह थोड़ा सा काउंटर-अंतर्ज्ञानी है कि प्रतिलिपि बनाने वाले को निजी नहीं बनाया जा सकता है। – BreakDS

+0

@ ब्रेकड्स: यदि कन्स्ट्रक्टर 'अस्वीकरण' है तो कॉपी कन्स्ट्रक्टर को निजी (एक मानक मानक लाइब्रेरी कार्यान्वयन मानना) बनाया जा सकता है। – ildjarn

9

पिछले उत्तर द्वारा सुझाए गए अनुसार, gcc 4.7 गलत इस कोड को अस्वीकार करने के लिए, एक गलती जो corrected in gcc 4.8 है।

पूर्ण मानक अनुरूप व्यवहार vector<T>::push_back के लिए है:

  • अगर वहाँ केवल एक प्रति निर्माता और कोई कदम निर्माता, push_back अपने तर्क कॉपी जाएगा और मजबूत अपवाद सुरक्षा की गारंटी दे देंगे। यही है, यदि वेक्टर स्टोरेज के पुनर्वितरण द्वारा ट्रिगर किए गए अपवाद के कारण push_back विफल रहता है, तो मूल वेक्टर अपरिवर्तित और उपयोग योग्य रहेगा। यह सी ++ 98 से ज्ञात व्यवहार है और यह भी गड़बड़ी का कारण है।
  • यदि T के लिए noexcept चालक कन्स्ट्रक्टर है, push_back को इसके तर्क से स्थानांतरित करेगा और मजबूत अपवाद गारंटी देगा। यहां कोई आश्चर्य नहीं है।
  • अगर वहाँ एक चाल निर्माता कि नहींnoexcept है और वहाँ भी एक प्रति निर्माता है, push_backहोगा प्रतिलिपि वस्तु और मजबूत अपवाद सुरक्षा की गारंटी दे। यह पहली नज़र में अप्रत्याशित है। जबकि push_back यहां स्थानांतरित हो सकता है, यह मजबूत अपवाद गारंटी बलिदान के खर्च पर ही संभव होगा। यदि आपने सी ++ 98 से सी ++ 11 तक कोड पोर्ट किया है और आपका प्रकार चल रहा है, तो यह चुपचाप मौजूदा push_back कॉल के व्यवहार को बदल देगा। इस गड़बड़ी से बचने और सी ++ 98 कोड के साथ संगतता बनाए रखने के लिए, सी ++ 11 धीमी प्रतिलिपि पर वापस आ जाता है। जीसीसी 4.7 व्यवहार यही है। लेकिन और भी है ...
  • अगर वहाँ एक चाल निर्माता कि noexcept नहीं है, लेकिन कोई नकल निर्माता बिल्कुल है - जो है, तत्व केवल ले जाया जा सकता है और नहीं की नकल की - push_back चाल प्रदर्शन करेंगे लेकिन नहीं मजबूत अपवाद सुरक्षा की गारंटी दे देंगे। यह वह जगह है जहां जीसीसी 4.7 गलत हो गया। सी ++ 98 में push_back एस ऐसे प्रकार के लिए नहीं हैं जो चलने योग्य हैं लेकिन कॉपी करने योग्य नहीं हैं। तो यहां मजबूत अपवाद सुरक्षा का त्याग करना मौजूदा कोड को तोड़ नहीं देता है। यही कारण है कि इसकी अनुमति है और मूल कोड वास्तव में कानूनी सी ++ 11 है।

push_back पर cppreference.com देखें: एक अपवाद फेंक दिया है

हैं, तो इस समारोह कोई प्रभाव (मजबूत अपवाद गारंटी) है।

यदि टी के चालक कन्स्ट्रक्टर को अस्वीकार्य नहीं है और प्रतिलिपि बनाने योग्य नहीं है, तो वेक्टर फेंकने की गति कन्स्ट्रक्टर का उपयोग करेगा। अगर यह फेंकता है, गारंटी माफ कर दी गई है और प्रभाव निर्दिष्ट नहीं हैं।

या सी ++ 11 मानक (मेरे द्वारा अतिरिक्त बल) से थोड़ा और अधिक जटिल §23.3.6.5:

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

या आप (के बारे में 00:42:00 पर शुरू 00:30:20 पर दिलचस्प भाग के साथ) पढ़ने, Scott Meyer's Going Native 2013 talk पसंद नहीं है अगर।

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