2016-08-17 14 views
6

निम्नलिखित कोड पर विचार करें? N3797 के अपने प्रतिलिपि में यहसमेकन की प्रारंभिक सूची: जब यह कॉपी कन्स्ट्रक्टर का आह्वान कर सकता है?</p> <pre><code>struct A { int x; }; int main() { A a; A b{a}; } </code></pre> <p>इस कार्यक्रम सी ++ 11 मानक में अच्छी तरह से गठित है:

8.5.4 सूची प्रारंभ कहते [dcl.init.list]

3: इस प्रकार एक वस्तु या प्रकार T के संदर्भ की सूची-प्रारंभ परिभाषित किया गया है:
- अगर T एक समग्र है, कुल प्रारंभिक प्रदर्शन किया जाता है (8.5.1)।
- अन्यथा, Tstd::initializer_list<E> का एक विशेषज्ञता है, ...
- अन्यथा, यदि T एक वर्ग प्रकार है, तो रचनाकारों पर विचार किया जाता है। लागू कन्स्ट्रक्टर की गणना की जाती है और अधिभार संकल्प का उपयोग करके सबसे अच्छा चुना जाता है। यदि किसी भी प्रकार को बदलने के लिए एक संकीर्ण रूपांतरण की आवश्यकता है, तो कार्यक्रम खराब हो गया है।
- अन्यथा, यदि प्रारंभकर्ता सूची में E प्रकार का एक तत्व है और या तो T संदर्भ प्रकार नहीं है या यह संदर्भ E से संबंधित है, तो ऑब्जेक्ट या संदर्भ उस तत्व से प्रारंभ किया गया है; यदि तत्व को T में परिवर्तित करने के लिए एक संकीर्ण रूपांतरण की आवश्यकता है, तो प्रोग्राम खराब हो गया है।
- अन्यथा, यदि T एक संदर्भ प्रकार है, तो T द्वारा प्रकार संदर्भ का एक pr-value अस्थायी है प्रतिलिपि-प्रारंभिक या प्रत्यक्ष-सूची-प्रारंभिक, संदर्भ के प्रारंभिक प्रकार के आधार पर, और संदर्भ है उस अस्थायी के लिए बाध्य।
- अन्यथा, अगर प्रारंभकर्ता सूची में कोई तत्व नहीं है, तो वस्तु मान-प्रारंभिक है।
- अन्यथा, कार्यक्रम खराब गठित है।

उदाहरण का बिंदु यह है कि प्रकार एक समग्र है, लेकिन सूची-प्रारंभिक प्रतिलिपि प्रतिलिपि बनाने का अनुमान है। gcc 4.8 और gcc 4.9, सी ++ 11 मानक पर, यह विफल रहता है:

main.cpp: In function ‘int main()’: 
main.cpp:7:8: error: cannot convert ‘A’ to ‘int’ in initialization 
    A b{a}; 
     ^

और A is not convertible to int या इसी तरह कहते हैं, क्योंकि कुल प्रारंभ विफल रहता है। gcc 5.4 पर, यह C++ 11 मानक पर ठीक काम करता है।

clang पर आपको clang-3.5, 3.6 के साथ समान त्रुटियां मिलती हैं, और यह clang-3.7 पर काम करना शुरू कर देती है।

मैं समझता हूं कि यह सी ++ 14 मानक पर अच्छी तरह से गठित है, और यह एक दोष रिपोर्ट here में उल्लिखित है।

हालांकि, मुझे समझ में नहीं आता है कि इसे मानक में दोष क्यों माना जाता है।

जब मानक लिखते हैं,

"अगर X, foo-प्रारंभ किया जाता है। अन्यथा, यदि Y, बार-प्रारंभ किया जाता है, .... नहीं तो, कार्यक्रम बीमार ही बना है।",

इसका मतलब यह नहीं है कि अगर X रखता है, लेकिन foo-startization निष्पादित नहीं किया जा सकता है, तो हमें जांच करनी चाहिए कि Y है, और फिर बार-प्रारंभ करने का प्रयास करें?

यह उदाहरण काम करेगा, क्योंकि जब कुल प्रारंभिक विफलता होती है, तो हम std::initializer_list से मेल नहीं खाते हैं, और अगली स्थिति हम मेल खाते हैं "T एक वर्ग प्रकार है", और फिर हम निर्माता पर विचार करते हैं।

ध्यान दें कि यह यह कैसे इस संशोधित उदाहरण में काम करता है होना प्रतीत होता है

struct A { 
    int x; 
}; 

int main() { 
    A a; 
    const A & ref; 
    A b{ref}; 
} 

सभी एक ही compilers इस पहले उदाहरण के रूप में एक ही तरह से व्यवहार करते हैं, पर सी ++ 11 और सी ++ 14 मानकों। लेकिन ऐसा लगता है कि सीडब्ल्यूजी दोष रिकॉर्ड से संशोधित शब्द इस मामले पर लागू नहीं होता है। यह लिखा है:

तो T एक वर्ग प्रकार है और प्रारंभकर्ता सूची प्रकार cv T या एक वर्ग प्रकार T से प्राप्त की एक एकल तत्व है, उद्देश्य यह है कि तत्व से आरंभ नहीं हो जाता।

http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1467

लेकिन दूसरे कोड के उदाहरण में, प्रारंभकर्ता सूची तकनीकी रूप से const T & शामिल हैं। इसलिए मैं नहीं देखता कि यह कैसे काम करेगा जब तक कि कुल प्रारंभिक विफल होने के बाद, हमें रचनाकारों का प्रयास करना चाहिए।

क्या मैं गलत हूँ? क्या कुल प्रारंभिक विफल होने के बाद इसे रचनाकारों का प्रयास नहीं करना चाहिए?

यहाँ एक संबंधित उदाहरण है:

#include <iostream> 

struct B { 
    int x; 

    operator int() const { return 2; } 
}; 

int main() { 
    B b{1}; 
    B c{b}; 
    std::cout << c.x << std::endl; 
} 

clang-3.6, gcc-4.8, gcc-4.9 में, यह 2 प्रिंट, और clang-3.7 में, gcc-5.0 यह 1 प्रिंट करता है।

मान लीजिए कि मैं गलत हूं, और सी ++ 11 मानक पर, कुल मिलाकर प्रारंभिक सूची को प्रारंभिक प्रारंभिक माना जाना चाहिए और कुछ भी नहीं, जब तक कि दोष रिपोर्ट में नया शब्द पेश नहीं किया जाता है, क्या यह एक बग है तब भी होता है जब मैं नए कंपाइलर्स पर -std=c++11 का चयन करता हूं?

उत्तर

3

जब मानक लिखते हैं,

"अगर X, foo-प्रारंभ किया जाता है। अन्यथा, यदि Y, बार-प्रारंभ किया जाता है, ... इसका मतलब यह नहीं

करता है कि यदि X रखती है, लेकिन foo-प्रारंभ नहीं किया जा सकता है, तो हम जाँच करनी चाहिए अगर Y रखती है, और फिर प्रयास बार-आरंभीकरण?

नहीं। X पर हम फू-प्रारंभिक प्रदर्शन करते हैं। यदि यह विफल रहता है तो कार्यक्रम खराब हो गया है।

+0

तो आप 'संरचना बी' उदाहरण के बारे में क्या सोचते हैं? आपको लगता है कि 'जीसीसी' और 'क्लैंग' कुछ सी ++ 14 फीचर का उपयोग कर रहे हैं जो सी ++ 11 मानक में उपलब्ध नहीं होना चाहिए? –

+0

@ क्रिसबैक: मुझे लगता है कि उन्होंने फैसला किया है कि यह सी ++ 11 मानक में स्पष्ट दोष था, और उन्होंने निश्चित संस्करण लागू किया है। मुझे संदेह है कि इसे "हल" करने का एकमात्र कारण यह नहीं था कि उन्होंने सी ++ को बहुत तेज़ रिलीज़ करना शुरू कर दिया है, इसलिए पुराने मानकों में दोषों को ठीक करने के बजाय, वे इसे नवीनतम में ठीक कर देते हैं। –

4

जब मानक लिखते हैं,

"यदि एक्स, foo-प्रारंभ किया जाता है। अन्यथा, यदि वाई, बार-प्रारंभ किया जाता है, .... नहीं तो, कार्यक्रम बीमार ही बना है।",

यह अर्थ नहीं है कि अगर एक्स रखती है, लेकिन foo-प्रारंभ नहीं किया जा सकता है, तो हम अगर वाई रखती है की जाँच करनी चाहिए, और फिर प्रयास बार-आरंभीकरण?

नहीं है, यदि ऐसा नहीं होता । वास्तविक कोड है जैसे कि यह के बारे में सोचो:

T *p = ...; 
if(p) 
{ 
    p->Something(); 
} 
else 
{ ... } 

p शून्य नहीं है यही कारण है कि यह या तो एक वैध सूचक है मतलब यह नहीं है एक को नष्ट कर दिया वस्तु को p अंक, p->Something() ऐसा न करने पर आप को छोड़ करने के लिए पैदा नहीं होगा।। else। आपको कॉल की सुरक्षा करने का मौका मिला था स्थिति में

तो आपको अपरिभाषित व्यवहार मिलता है।

वही यहां जाता है। यदि एक्स, ए करते हैं तो यह नहीं दर्शाता है कि अगर कोई विफल रहता है तो क्या होता है; यह आपको यह करने के लिए कहता है। यदि यह नहीं किया जा सकता है ... आप खराब हो गए हैं।

+0

तो आपको लगता है कि 'स्ट्रक्चर बी' के साथ मेरे उदाहरण में, 'gcc-5' को' gcc-4.8' और 'gcc-4.9'' के समान व्यवहार करना चाहिए, जब 'std = C++ 11'? –

+0

@ क्रिसबैक: यह एक * अलग * प्रश्न है। यह एक सवाल है कि क्या दोष सुधार को मौजूदा मानकों पर पूर्ववत रूप से लागू किया जाना चाहिए। और उस का जवाब आम तौर पर बोल रहा है, हां। यही एक दोष रिपोर्ट * है *; यह मानक में एक * बग * है। बग को ठीक किया जाना चाहिए, और आपको यह कहना नहीं चाहिए कि आप उन्हें पाने के लिए अगले संस्करण का उपयोग कर रहे हैं, है ना? –

+0

मेरा मतलब मानक के कार्यान्वयन में एक बग और मानक के शब्दों में एक दोष के बीच एक अंतर है। पूर्व, हाँ, जिसे रिलीज द्वारा हल किया जाना चाहिए केवल आदर्श रूप से पैच-स्तर को बढ़ाने के लिए। लेकिन अगर मैं कहता हूं कि 'std = C++ 11' मैं आमतौर पर मानता हूं कि वे N3797 को लागू करने की कोशिश कर रहे हैं। अन्यथा इसका मतलब है कि मैं वास्तव में नहीं जानता कि संकलक तब तक करने का प्रयास करेगा जब तक कि मैं सभी मानकों को पढ़ता हूं। या मुझे लोगों को बताना है "आप संस्करण 3.6 के बाद क्लैंग का उपयोग नहीं कर सकते हैं, या दुर्भाग्यवश यह संकलित होगा लेकिन इंटिलाइजेशन इरादे की तरह काम नहीं करेगा और आप 2" –

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