C++ 17 में गैर-प्रतिलिपि योग्य चर के लिए सदस्य आरंभीकरण




initialization language-lawyer (2)

गैर-प्रतिलिपि योग्य चर (जैसे कि std::atomic<int> ) के लिए सदस्य आरंभीकरण करते समय, here उत्तर के अनुसार copy-initialization बजाय direct-initialization का उपयोग करना आवश्यक here । हालाँकि जब मैं g++ 7.4.0 में -std=c++17 को चालू करता -std=c++17 , तो ऐसा लगता है कि बाद वाला भी अच्छा काम करता है।

#include <atomic>

class A {
    std::atomic<int> a = 0;     // copy-initialization
    std::atomic<int> b{0};      // direct-initialization
};
$ g++ -c atomic.cc -std=c++11    // or c++14
atomic.cc:4:26: error: use of deleted function std::atomic<int>::atomic(const std::atomic<int>&)’
     std::atomic<int> a = 0;     // copy-initialization

$ g++ -c atomic.cc -std=c++17
// no error

जब यह g++ 6.5.0 साथ -std=c++17 साथ संकलित होने पर भी विफल रहा। यहाँ कौन सा सही है?


यहाँ कौन सा सही है?

7.4.0 सही है। इस मामले के लिए प्रतिलिपि बनाई जा सकती है, यही वजह है कि यह ठीक है। (हालांकि इसके लिए c ++ 17 की आवश्यकता होती है)।

(अधिक जानकारी के लिए https://en.cppreference.com/w/cpp/language/copy_initialization देखें)


व्यवहार C ++ 17 के बाद से बदल गया है, जिसके लिए कंपाइलर्स को std::atomic<int> a = 0; में कॉपी / मूव कंस्ट्रक्शन को छोड़ना पड़ता है std::atomic<int> a = 0; , यानी गारंटीकृत कॉपी एलिसन

(जोर मेरा)

निम्न परिस्थितियों में, संकलक को कक्षा की वस्तुओं की प्रतिलिपि बनाने और स्थानांतरित करने की आवश्यकता होती है, भले ही प्रतिलिपि / चाल निर्माणकर्ता और विध्वंसक के पास अस्पष्ट दुष्प्रभाव हों। वस्तुओं को सीधे भंडारण में निर्मित किया जाता है, जहां उन्हें अन्यथा कॉपी / स्थानांतरित किया जाएगा। कॉपी / मूव कंस्ट्रक्टर को मौजूद या सुलभ होने की आवश्यकता नहीं है, क्योंकि भाषा के नियम यह सुनिश्चित करते हैं कि कोई भी कॉपी / मूव ऑपरेशन न हो, यहाँ तक कि वैचारिक रूप से भी :

विवरण में, std::atomic<int> a = 0; प्रतिलिपि आरंभीकरण करता है :

यदि T एक वर्ग प्रकार है, और अन्य प्रकार के cv-unqualified संस्करण T से या T से व्युत्पन्न नहीं है, या यदि T गैर-वर्ग प्रकार है, लेकिन अन्य का प्रकार एक वर्ग प्रकार, उपयोगकर्ता-परिभाषित रूपांतरण अनुक्रम है। जो दूसरे के प्रकार से T में परिवर्तित हो सकता है (या T से व्युत्पन्न एक प्रकार से यदि T एक वर्ग प्रकार है और एक रूपांतरण फ़ंक्शन उपलब्ध है) की जांच की जाती है और सर्वश्रेष्ठ को अधिभार संकल्प के माध्यम से चुना जाता है। रूपांतरण का परिणाम, जो एक prvalue temporary (until C++17) prvalue expression (since C++17) यदि एक prvalue expression (since C++17) कंस्ट्रक्टर का उपयोग किया गया था, तो इसका उपयोग ऑब्जेक्ट को डायरेक्ट-इनिशियलाइज़ करने के लिए किया जाता है।

तथा

(जोर मेरा)

यदि T एक वर्ग प्रकार है और इनिशलाइज़र एक प्रचलित अभिव्यक्ति है, जिसका cv-unqualified प्रकार टी के समान वर्ग है, तो इनिशियलाइज़र एक्सप्रेशन स्वयं, इसके बजाय एक अस्थायी सामग्री से, गंतव्य ऑब्जेक्ट को इनिशियलाइज़ करने के लिए उपयोग किया जाता है

इसका मतलब a कि a को सीधे 0 से इनिशियलाइज़ किया गया है, इसका निर्माण करने के लिए कोई अस्थायी नहीं है और फिर इससे कॉपी / स्थानांतरित करने के लिए अस्थायी नहीं रह गया है।

C ++ 17 से पहले, अवधारणा std::atomic<int> a = 0; एक अस्थायी std::atomic आवश्यकता होती है std::atomic 0 से निर्मित होने के लिए std::atomic , फिर अस्थायी का उपयोग कॉपी-निर्माण करने के लिए किया जाता a

यहां तक ​​कि C ++ 17 से पहले भी नकल की अनुमति दी जाती है, इसे अनुकूलन माना जाता है:

(जोर मेरा)

यह एक अनुकूलन है: यहां तक ​​कि जब यह होता है और कॉपी / move (since C++11) कंस्ट्रक्टर को नहीं बुलाया जाता है, तब भी यह मौजूद होना चाहिए और पहुंच योग्य होना चाहिए (जैसे कि कोई अनुकूलन बिल्कुल नहीं हुआ), अन्यथा प्रोग्राम बीमार है- गठित :

यही कारण है कि जीसीएस सी के लिए प्री-सी ++ 17 मोड में नैदानिक ​​ट्रिगर करता है std::atomic<int> a = 0;

(जोर मेरा)

नोट: ऊपर दिया गया नियम एक अनुकूलन निर्दिष्ट नहीं करता है: C ++ 17 मूल भाषा के प्रचलन और अस्थायीताओं के विनिर्देश मूलभूत रूप से पहले के C ++ संशोधनों से भिन्न हैं: अब कॉपी / से स्थानांतरित करने के लिए अस्थायी नहीं है । C ++ 17 यांत्रिकी का वर्णन करने का एक और तरीका है "अनमैटेरिज्ड वैल्यू पासिंग": प्रचलन को लौटाया जाता है और इसका उपयोग बिना अस्थायी सामग्री के कभी भी किया जाता है

BTW: मुझे लगता है कि वहाँ एक बग था g++ 6.5.0 साथ -std=c++17 ; और इसे बाद के संस्करण में तय किया गया है।





copy-elision