Ich habe in der folgenden Situation ein sehr seltsames Verhalten (bei Clang und GCC) festgestellt. Ich habe einen Vektor nodes
mit einem Element, einer Klasseninstanz Node
. Ich rufe dann eine Funktion auf nodes[0]
, die Node
dem Vektor eine neue hinzufügt . Wenn der neue Knoten hinzugefügt wird, werden die Felder des aufrufenden Objekts zurückgesetzt! Sie scheinen jedoch nach Beendigung der Funktion wieder normal zu werden.
Ich glaube, dies ist ein minimal reproduzierbares Beispiel:
#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;
}
Welche Ausgänge
Before, X = 3
After, X = 0
Finally, X = 3
Sie würden jedoch erwarten, dass X durch den Prozess unverändert bleibt.
Andere Dinge, die ich versucht habe:
- Wenn ich die Zeile entferne, die ein
Node
Inneres hinzufügtset()
, wird jedes Mal X = 3 ausgegeben. - Wenn ich ein neues erstelle
Node
und es auf dem (Node p = nodes[0]
) aufrufe, ist die Ausgabe 3, 3, 3 - Wenn ich eine Referenz erstelle
Node
und diese (Node &p = nodes[0]
) aufrufe, ist die Ausgabe 3, 0, 0 (möglicherweise liegt dies daran, dass die Referenz verloren geht, wenn die Größe des Vektors geändert wird?)
Ist das undefiniertes Verhalten aus irgendeinem Grund? Warum?
reserve(2)
den Vektor vor dem Aufruf aufgerufenset()
hätten, wäre dies ein definiertes Verhalten. Das Schreiben einer solchen Funktionset
erfordert jedoch, dass der Benutzerreserve
vor dem Aufrufen eine ausreichende Größe hat, um undefiniertes Verhalten zu vermeiden. Dies ist ein schlechtes Design. Tun Sie es also nicht.