Я обнаружил очень странное поведение (на Clang и GCC) в следующей ситуации. У меня есть вектор, 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()
, то каждый раз выводится X = 3. - Если я создаю новый
Node
и вызываю его на то (Node p = nodes[0]
), то результат будет 3, 3, 3 - Если я создаю ссылку
Node
и вызываю ее дляNode &p = nodes[0]
this ( ), то вывод будет равен 3, 0, 0 (возможно, это происходит потому, что ссылка теряется при изменении размера вектора?)
Это неопределенное поведение по какой-то причине? Почему?
reserve(2)
вектор перед вызовом,set()
это было бы определенным поведением. Но написание подобной функцииset
требует от пользователяreserve
достаточно подходящего размера перед вызовом, чтобы избежать неопределенного поведения, и это плохой дизайн, поэтому не делайте этого.