Я обнаружил очень странное поведение (на 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достаточно подходящего размера перед вызовом, чтобы избежать неопределенного поведения, и это плохой дизайн, поэтому не делайте этого.