Znalazłem bardzo dziwne zachowanie (na clang i GCC) w następującej sytuacji. Mam wektor, nodes
z jednym elementem, instancją klasy Node
. Następnie wywołuję funkcję, nodes[0]
która dodaje nową wartość Node
do wektora. Po dodaniu nowego węzła pola obiektu wywołującego są resetowane! Wydają się jednak wracać do normy po zakończeniu funkcji.
Uważam, że jest to minimalny, powtarzalny przykład:
#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;
}
Które wyjścia
Before, X = 3
After, X = 0
Finally, X = 3
Chociaż można oczekiwać, że X pozostanie niezmieniony przez ten proces.
Inne rzeczy, których próbowałem:
- Jeśli usunę linię, która dodaje
Node
wnętrzeset()
, to za każdym razem wyprowadza X = 3. - Jeśli utworzę nowy
Node
i wywołam go na tym (Node p = nodes[0]
), wówczas wynikiem będzie 3, 3, 3 - Jeśli utworzę odwołanie
Node
i wywołam go na tym (Node &p = nodes[0]
), wówczas wynikiem będzie 3, 0, 0 (być może jest to spowodowane tym, że odwołanie zostało utracone, gdy wektor zmienia rozmiar?)
Czy z jakiegoś powodu jest to niezdefiniowane zachowanie? Dlaczego?
reserve(2)
wektor przed wywołaniem,set()
byłoby to zdefiniowane zachowanie. Ale napisanie takiej funkcjiset
wymaga od użytkownika odpowiedniegoreserve
rozmiaru przed wywołaniem jej, aby uniknąć nieokreślonego zachowania jest złym projektem, więc nie rób tego.