5

निम्नलिखित कार्यक्रम में:मूल्यांकन आदेश

#include <iostream> 
struct I { 
    int i; 
    I(){i=2;} 
    I(int _i){i=_i;} 
}; 
int a[3] = {a[2] = 1}; 
int aa[3][3] = {aa[2][2] = 1}; 
I A[3] = {A[2].i = 1}; 
I AA[3][3] = {AA[2][2].i = 1}; 
int main(int argc, char **argv) { 
    for (int b : a) std::cout << b << ' '; 
    std::cout << '\n'; 
    for (auto &bb : aa) for (auto &b : bb) std::cout << b << ' '; 
    std::cout << '\n'; 
    for (auto &B : A) std::cout << B.i << ' '; 
    std::cout << '\n'; 
    for (auto &BB : AA) for (auto &B : BB) std::cout << B.i << ' '; 
    std::cout << '\n'; 
    return 0; 
} 

उत्पादन

1 0 0 
1 0 0 0 0 0 0 0 1 
1 2 2 
1 2 2 2 2 2 2 2 2 
http://ideone.com/1ueWdK से clang3.7

साथ

है, लेकिन परिणाम है:

0 0 1 
1 0 0 0 0 0 0 0 1 
1 2 2 
1 2 2 2 2 2 2 2 2 

http://rextester.com/l/cpp_online_compiler_clang पर भी क्लैंग 3.7 के साथ।

अपने स्वयं के उबंटू पर, जीसीसी 6.2 int aa[3][3] = {aa[2][2] = 1} पर एक आंतरिक कंपाइलर त्रुटि प्रदान करता है।

मुझे लगता है कि यह अपरिभाषित व्यवहार है, लेकिन मानक में एक निश्चित विवरण नहीं मिल रहा है।

सवाल यह है:

चाहे प्रारंभकर्ता सूची (जैसे a[2] = 1) और सरणी की वास्तविक तत्व के प्रारंभ में काम पर दुष्प्रभाव के मूल्यांकन के क्रम (जैसे a[2]) मानक में परिभाषित?

इसे स्पष्ट रूप से परिभाषित या अपरिभाषित कहा गया है? या यह अपरिभाषित हो जाता है क्योंकि यह स्पष्ट रूप से परिभाषित नहीं है?

या क्या निर्माण ने मूल्यांकन आदेश से अलग अन्य कारणों से व्यवहार को परिभाषित या अपरिभाषित किया है?

+0

मेरी आंखें खून बह रही हैं ... यदि यह कोई उत्थान नहीं है, तो मुझे नहीं पता कि क्या होगा ... –

+0

[संकलित नहीं करता] (http://ideone.com/ZT1N3K)। इसके अलावा आंतरिक कंपाइलर त्रुटियों का परिणाम हो सकता है यदि आपका कोड इतना गड़बड़ हो गया है कि कंपाइलर का पार्सर उड़ाता है। – PaulMcKenzie

+0

जीसीसी 4.9 और क्लैंग में संकलित ... gcc 5+ में एक बग है –

उत्तर

4

के सबसे सामान्य स्थिति से शुरू करते हैं:

I A[3] = {A[2].i = 1}; 
I AA[3][3] = {AA[2][2].i = 1}; 

इन दोनों यूबी, [basic.life] के उल्लंघन के कारण कर रहे हैं। आप अपने जीवनकाल शुरू होने से पहले किसी वस्तु के मूल्य तक पहुंच रहे हैं। I में एक मामूली डिफ़ॉल्ट कन्स्ट्रक्टर नहीं है, और इसलिए वैक्यूश प्रारंभ नहीं किया जा सकता है। इसलिए, ऑब्जेक्ट का जीवनकाल केवल एक बार कन्स्ट्रक्टर पूरा हो जाने पर ही शुरू होता है। जब आप उस सरणी के तत्वों तक पहुंच रहे हों तो A सरणी के तत्व अभी तक नहीं बनाए गए हैं।

इसलिए, आप अभी तक निर्मित वस्तु का उपयोग करके यूबी का आह्वान कर रहे हैं। के रूप में [basic.life]/1 द्वारा परिभाषित

int a[3] = {a[2] = 1}; 
int aa[3][3] = {aa[2][2] = 1}; 

देखें, int परमिट "असार प्रारंभ",:

अब, अन्य दो मामलों अधिक जटिल हैं। a और aa के लिए संग्रहण अधिग्रहित किया गया है। इसलिए, int a[3]int ऑब्जेक्ट्स की वैध सरणी है, भले ही कुल प्रारंभिकरण अभी तक शुरू नहीं हुआ है। इसलिए ऑब्जेक्ट तक पहुंच और यहां तक ​​कि इसकी स्थिति भी स्थापित करना यूबी नहीं है।

यहां संचालन का आदेश तय किया गया है। यहां तक ​​कि पूर्व-सी ++ 17, प्रारंभिक सूची के तत्वों की प्रारंभिकता को प्रारंभिक प्रारंभिकता से पहले अनुक्रमित किया जाता है, जैसा कि [dcl.init.list]/4 में बताया गया है। कुल मिलाकर तत्व जो प्रारंभिक सूची में सूचीबद्ध नहीं हैं, वे typename{} संरचनाओं द्वारा भरे जाएंगे।int{} का मतलब के लिए मूल्य आरंभ कर देगा एक int, जो 0.

तो भले ही आप a[2] सेट और aa[2][2] में परिणाम है, वे तुरंत कुल आरंभीकरण के माध्यम से ओवरराइट किया जाना चाहिए।

इसलिए, इन सभी कंपाइलर्स गलत हैं। इस सवाल का जवाब होना चाहिए:

1 0 0 
1 0 0 0 0 0 0 0 0 

अब दी, यह सब बहुत बेवकूफ है और आप इसे नहीं करना चाहिए। लेकिन एक शुद्ध भाषा परिप्रेक्ष्य से, यह अच्छी तरह से परिभाषित व्यवहार है।

+0

एक छोटा नाइटपिक: उनके जीवनकाल से पहले वस्तुओं का उपयोग करने के लिए एक विशेष प्रावधान है [यहां] (http://eel.is/c++draft/basic .life # 6), जो [इस खंड] की ओर जाता है (http://eel.is/c++draft/class.cdtor#1) कह रहा है कि ऑब्जेक्ट के कन्स्ट्रक्टर के शुरू होने पर आप ऑब्जेक्ट सदस्यों तक पहुंच सकते हैं - नहीं ख़त्म होना। – krzaq

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