Tôi đã tìm thấy một số hành vi rất kỳ lạ (trên clang và GCC) trong tình huống sau đây. Tôi có một vectơ, nodes
với một phần tử, một thể hiện của lớp Node
. Sau đó tôi gọi một hàm trên nodes[0]
đó thêm một cái mới Node
vào vector. Khi Node mới được thêm vào, các trường của đối tượng gọi được đặt lại! Tuy nhiên, chúng dường như trở lại bình thường một lần nữa khi chức năng kết thúc.
Tôi tin rằng đây là một ví dụ có thể tái tạo tối thiểu:
#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;
}
Đầu ra nào
Before, X = 3
After, X = 0
Finally, X = 3
Mặc dù bạn sẽ mong đợi X không thay đổi theo quy trình.
Những thứ khác tôi đã thử:
- Nếu tôi loại bỏ dòng có thêm một
Node
bên trongset()
, thì nó sẽ xuất X = 3 mỗi lần. - Nếu tôi tạo một cái mới
Node
và gọi nó trên đó (Node p = nodes[0]
) thì đầu ra là 3, 3, 3 - Nếu tôi tạo một tham chiếu
Node
và gọi nó trên đó (Node &p = nodes[0]
) thì đầu ra là 3, 0, 0 (có lẽ điều này là do tham chiếu bị mất khi vectơ thay đổi kích thước?)
Đây có phải là hành vi không xác định vì một số lý do? Tại sao?
reserve(2)
vectơ trước khi gọiset()
thì đây sẽ là hành vi được xác định. Nhưng việc viết một hàm như thếset
đòi hỏi người dùng phảireserve
có kích thước phù hợp trước khi gọi nó để tránh hành vi không xác định là thiết kế xấu, vì vậy đừng làm điều đó.