Я знайшов дуже дивну поведінку (на кланг та 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]
), то вихід 3, 0, 0 (можливо, це тому, що посилання втрачається, коли розмір вектора змінюється?)
Чи є це невизначена поведінка чомусь? Чому?
reserve(2)
вектор до виклику,set()
це визначатиметься поведінкою. Але написання такої функціїset
вимагає від користувачаreserve
достатньо достатнього розміру, перш ніж викликати її, щоб уникнути невизначеної поведінки - це поганий дизайн, тому не робіть цього.