मैंने निम्नलिखित स्थिति में कुछ बहुत ही अजीब व्यवहार (क्लैंग और जीसीसी पर) पाया है। मेरे पास एक वेक्टर है, nodes
जिसमें एक तत्व, कक्षा का एक उदाहरण है Node
। मैं तब एक फ़ंक्शन को कॉल करता हूं जो वेक्टर में nodes[0]
एक नया जोड़ता है Node
। जब नया नोड जोड़ा जाता है, तो कॉलिंग ऑब्जेक्ट के फ़ील्ड रीसेट हो जाते हैं! हालाँकि, कार्य समाप्त होने के बाद वे फिर से सामान्य हो जाते हैं।
मेरा मानना है कि यह एक न्यूनतम प्रजनन योग्य उदाहरण है:
#include <iostream>
#include <vector>
using namespace std;
struct Node;
vector<Node> nodes;
struct Node{
int X;
void set(){
X = 3;
cout << "Before, X = " << X << endl;
nodes.push_back(Node());
cout << "After, X = " << X << endl;
}
};
int main() {
nodes = vector<Node>();
nodes.push_back(Node());
nodes[0].set();
cout << "Finally, X = " << nodes[0].X << endl;
}
जो आउटपुट देता है
Before, X = 3
After, X = 0
Finally, X = 3
हालाँकि आप उम्मीद करेंगे कि X प्रक्रिया से अपरिवर्तित रहेगा।
अन्य चीजें जो मैंने कोशिश की हैं:
- अगर मैं उस लाइन को हटाता हूं जो
Node
अंदर जोड़ता हैset()
, तो यह हर बार एक्स = 3 को आउटपुट करता है। - यदि मैं एक नया बनाता हूं
Node
और उस पर कॉल करता हूं (Node p = nodes[0]
) तो आउटपुट 3, 3, 3 है - यदि मैं एक संदर्भ बनाता हूं
Node
और उस पर कॉल करता हूं (Node &p = nodes[0]
) तो आउटपुट 3, 0, 0 है (शायद यह एक है क्योंकि वेक्टर के आकार बदलने पर संदर्भ खो जाता है?)
क्या यह अपरिभाषित व्यवहार किसी कारण से है? क्यों?
reserve(2)
कॉलset()
करने से पहले वेक्टर पर बुलाया गया था तो यह परिभाषित व्यवहार होगा। लेकिन ऐसा फ़ंक्शन लिखना,set
जिसेreserve
अपरिभाषित व्यवहार से बचने के लिए उपयोगकर्ता को कॉल करने से पहले उचित रूप से पर्याप्त आकार की आवश्यकता होती है, यह खराब डिज़ाइन है, इसलिए ऐसा न करें।