I have found some very weird behaviour (on clang and GCC) in the following situation. I have a vector, nodes
, with one element, an instance of class Node
. I then call a function on nodes[0]
that adds a new Node
to the vector. When the new Node is added, the calling object's fields are reset! However, they seem to return to normal again once the function has finished.
I believe this is a minimal reproducible example:
#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; }
Which outputs
Before, X = 3 After, X = 0 Finally, X = 3
Though you would expect X to remain unchanged by the process.
Other things I have tried:
Node
inside set()
, then it outputs X = 3 every time.Node
and call it on that (Node p = nodes[0]
) then the output is 3, 3, 3Node
and call it on that (Node &p = nodes[0]
) then the output is 3, 0, 0 (perhaps this one is because the reference is lost when the vector resizes?)Is this undefined behaviour for some reason? Why?
Yes, std::vector<T>::push_back() creates a copy of the argument and stores it in the vector.
As a rule of thumb, you should use: a std::array if the size in fixed at compile time. a std::vector is the size is not fixed at compile time. a pointer on the address of their first element is you need low level access.
You can use the find function, found in the std namespace, ie std::find . You pass the std::find function the begin and end iterator from the vector you want to search, along with the element you're looking for and compare the resulting iterator to the end of the vector to see if they match or not.
Although std::vector can be used as a dynamic array, it can also be used as a stack.
Your code has undefined behavior. In
void set(){ X = 3; cout << "Before, X = " << X << endl; nodes.push_back(Node()); cout << "After, X = " << X << endl; }
The access to X
is really this->X
and this
is a pointer to the member of the vector. When you do nodes.push_back(Node());
you add a new element to the vector and that process reallocates, which invalidates all iterators, pointers and references to elements in the vector. That means
cout << "After, X = " << X << endl;
is using a this
that is no longer valid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With