जी ++ की बात क्या है -Wreorder?


150

G ++ -Wall ऑप्शन में -Wreorder शामिल है। यह विकल्प क्या करता है, नीचे वर्णित है। मेरे लिए यह स्पष्ट नहीं है कि कोई क्यों परवाह करेगा (विशेष रूप से इसे डिफ़ॉल्ट रूप से चालू करने के लिए -वैल-इन)।

-Wreorder (केवल C ++)
  चेतावनी जब कोड में दिए गए सदस्य initializers का आदेश नहीं करता है
  उस क्रम से मेल करें जिसमें उन्हें निष्पादित किया जाना चाहिए। उदाहरण के लिए:

    संरचना ए {
      int i;
      इंट जे;
      A (): j (0), i (1) {}
    };

  कंपाइलर i और j के लिए सदस्य इनिशियलाइज़र को फिर से व्यवस्थित करेगा
  सदस्यों की घोषणा के आदेश से मेल खाते हैं, उस के लिए एक चेतावनी फेंकना
  प्रभाव। यह चेतावनी -Wall द्वारा सक्षम है।

2
कुछ अच्छे जवाब यहाँ हैं, लेकिन एक मामले में यह किसी के लिए भी एक संक्षिप्त बात है: जी ++ के पास इसे एक पूर्ण-त्रुटि के रूप में व्यवहार करने के लिए एक ध्वज है:-Werror=reorder
मैक्स बैरक्लोफ़

जवाबों:


257

विचार करें:

struct A {
    int i;
    int j;
    A() : j(0), i(j) { }
};

अब iकुछ अज्ञात मान से आरंभ किया गया है, शून्य नहीं।

वैकल्पिक रूप से, प्रारंभिक के iकुछ दुष्प्रभाव हो सकते हैं जिसके लिए आदेश महत्वपूर्ण है। उदाहरण के लिए

A(int n) : j(n++), i(n++) { }

80
यह वास्तव में प्रलेखन में उदाहरण होना चाहिए।
बेन एस

3
धन्यवाद। हमारे अधिकांश प्रकारों के साथ POD प्रकार के शुरुआती इनिशियलाइज़र होते हैं जो मेरे साथ नहीं होते थे। आपका उदाहरण g ++ मैनुअल उदाहरण से बहुत बेहतर है।
Peeter Joot

5
@ यह इसलिए है क्योंकि आपका कंपाइलर (gcc) अनआर्गेनाइज्ड वैरिएबल्स को 0 से इनिशियलाइज़ करता है, लेकिन यह ऐसा कुछ नहीं है जिस पर आप निर्भर हैं; मैं 0 हो रहा हूँ,
अनइंस्टाल्यूटेड

2
@ यक ऑर्डर मैन पेज था-> एसओ उत्तर। यहां 2007 से मैन पेज का एक संग्रह है जो इस उदाहरण को स्पष्ट रूप से सूचीबद्ध करता है। बेन एस की अपभ्रंश टिप्पणी किसी का सुझाव है कि यह पहले से ही जाँच के बिना कुछ मौजूद है कि सुझाव का एक उल्लसित उदाहरण है। web.archive.org/web/20070712184121/http://linux.die.net/man/1/……
KymikoLoco

3
@KymikoLoco सिर्फ सादा गलत है। मैन पेज में उदाहरण ओपी से एक है (जहां iआरंभिक है 1)। यहाँ, iइसको आरंभीकृत किया गया है j, जो वास्तव में एक समस्या को प्रदर्शित करता है।
जाजपी 16

42

समस्या यह है कि कोई व्यक्ति कंस्ट्रक्टर में सदस्य आरंभीकरणकर्ताओं की सूची देख सकता है, और सोच सकता है कि उन्हें उस क्रम में निष्पादित किया गया है (जे पहले, फिर मैं)। वे नहीं हैं, वे उस क्रम में निष्पादित होते हैं जिस क्रम में सदस्यों को कक्षा में परिभाषित किया जाता है।

मान लीजिए आपने लिखा A(): j(0), i(j) {}। कोई व्यक्ति इसे पढ़ सकता है, और सोच सकता है कि मैं मान के साथ समाप्त होता है 0. यह नहीं है, क्योंकि आपने इसे जे के साथ आरंभीकृत किया है, जिसमें कबाड़ शामिल है क्योंकि यह स्वयं प्रारंभ नहीं हुआ है।

चेतावनी आपको लिखने के लिए याद दिलाती है A(): i(j), j(0) {}, जो उम्मीद है कि बहुत अधिक गड़बड़ दिखती है।


लगता है / वास्तव में गड़बड़ बदबू आ रही है! :) निश्चित रूप से कोड गंध :) आपके स्पष्ट स्पष्टीकरण के लिए धन्यवाद जो बिंदु पर सही है। :)
होगा

1
"... आपको A (): i (j), j (0) {} ..." लिखने की याद दिलाता है। मेरा सुझाव है कि यह आपको इस विशेष मामले में कक्षा के सदस्यों को फिर से लिखने की याद दिलाता है।
2.718

18

अन्य उत्तरों ने कुछ अच्छे उदाहरण दिए हैं जो चेतावनी के विकल्प को सही ठहराते हैं। मुझे लगा कि मैं कुछ ऐतिहासिक संदर्भ प्रदान करूंगा। C ++ के निर्माता बज़्ने स्ट्रॉस्ट्रुप ने अपनी पुस्तक द सी ++ प्रोग्रामिंग लैंग्वेज (तृतीय संस्करण, पेज 99) में बताया है:

सदस्यों के कंस्ट्रक्टरों को बुलाया जाता है, जिसमें पहले वाले कंस्ट्रक्टर के निष्कासन को निष्पादित किया जाता है। कंस्ट्रक्टर को उस क्रम में बुलाया जाता है, जिसमें वे उस क्रम के बजाय कक्षा में घोषित किए जाते हैं, जिसमें वे इनिशियलाइज़र सूची में दिखाई देते हैं। भ्रम से बचने के लिए, ऐलानर्स को घोषणा क्रम में निर्दिष्ट करना सबसे अच्छा है। सदस्य विध्वंसक को निर्माण के रिवर्स ऑर्डर में कहा जाता है।


10

यदि आपके इनिशियलाइज़र के साइड इफेक्ट्स हैं तो यह आपको काट सकता है। विचार करें:

int foo() {
    puts("foo");
    return 1;
}

int bar() {
    puts("bar");
    return 2;
}

struct baz {
    int x, y;
    baz() : y(foo()), x(bar()) {}
};

इसके बाद के संस्करण "बार" तब "फू" मुद्रित करेगा, भले ही सहज रूप से कोई यह मान ले कि ऑर्डर प्रारंभिक सूची में लिखा गया है।

वैकल्पिक रूप से, अगर xऔर yएक निर्माता के साथ कुछ उपयोगकर्ता-निर्धारित प्रकार के होते हैं, कि निर्माता भी साइड इफेक्ट, एक ही गैर स्पष्ट परिणाम के साथ हो सकता है।

यह स्वयं भी प्रकट हो सकता है जब एक सदस्य के लिए इनिशलाइज़र किसी अन्य सदस्य को संदर्भित करता है।


7

चेतावनी मौजूद है क्योंकि यदि आप सिर्फ कंस्ट्रक्टर को पढ़ते हैं, तो ऐसा लगता है कि jपहले से आरंभ किया जा रहा है i। यह एक समस्या बन जाती है यदि एक का उपयोग दूसरे को शुरू करने के लिए किया जाता है, जैसे कि

struct A {
  int i;
  int j;
  A(): j (0), i (this->j) { }
};

जब आप बस कंस्ट्रक्टर को देखते हैं, यह सुरक्षित दिखता है । लेकिन वास्तव में, jअभी तक उस बिंदु पर आरंभीकृत नहीं किया गया है जहां इसका उपयोग आरंभ करने के लिए किया जाता है i, और इसलिए कोड अपेक्षा के अनुरूप काम नहीं करेगा। इसलिए चेतावनी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.