Unexpected behavior when modifying a vector while calling push_back
I have a problem with the following Trie implementation.
Code 1 — RE
#include <bits/stdc++.h>
using namespace std;
struct Trie {
struct Node {
int child[2];
long long sum, val;
Node() {
child[0] = child[1] = -1;
sum = val = 0;
}
};
vector<Node> vtNode;
int root;
Trie() {
root = newNode();
}
int newNode() {
int id = (int)vtNode.size();
vtNode.push_back(Node());
return id;
}
int getBit(long long x, int i) {
return (x >> i) & 1;
}
void addNum(long long x) {
int p = root;
for (int i = 32; i >= 0; --i) {
int c = getBit(x, i);
if (vtNode[p].child[c] == -1) {
cerr << vtNode[p].child[c] << "\n";
vtNode[p].child[c] = newNode();
cerr << vtNode[p].child[c] << "\n";
}
p = vtNode[p].child[c];
}
}
};
int main() {
Trie trie;
trie.addNum(12345);
return 0;
}
Code 2 — works correctly
The only difference is that I store the result of newNode() in a local variable before modifying vtNode[p].child[c]:
void addNum(long long x) {
int p = root;
for (int i = 32; i >= 0; --i) {
int c = getBit(x, i);
if (vtNode[p].child[c] == -1) {
cerr << vtNode[p].child[c] << "\n";
int id = newNode();
vtNode[p].child[c] = id;
cerr << vtNode[p].child[c] << "\n";
}
p = vtNode[p].child[c];
}
}
The second version works as expected, while the first version gives unexpected results.
For the first version, cerr prints -1 again after newNode():
-1
-1
-1
...
while the second version prints increasing positive indices.
My question
Why does this happen?
I initially thought these two pieces of code were equivalent:
vtNode[p].child[c] = newNode();
and
int id = newNode();
vtNode[p].child[c] = id;
Is this related to vector::push_back() causing reallocation and invalidating something?
I would like to understand what happens during the evaluation of vtNode[p].child[c] = newNode(); and why storing the return value in a local variable changes the behavior.



