在向量中存储对象时的不良行为

Undesired behavior when storing object in vector

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;


struct Node {
    string name;
    vector<Node> nodes;
    Node(const string & name) : name(name) {}
    ~Node() {
        cout << "release " << name << endl;
    }
};

Node root {"A"};
unordered_map<string, Node*> m;

void add_child(const string & parent, const string & child) {
    if (!m.count(parent)) return;
    auto & p = *m[parent];
    cout << "add " << parent << endl;
    // Here is the bug
    p.nodes.emplace_back(child);
    m[child] = &p.nodes.back();
    cout << "add done " << parent << endl;
}

int main() {
    m["A"] = &root;
    vector<string> edges {"A", "B", "A", "D", "B", "E"};

    for (int i = 0; i < edges.size(); i += 2) {
        add_child(edges[i], edges[i + 1]);
    }
}

我正在构建一棵树,其中子节点直接存储为对象类型而不是指针类型。

每当我插入一个新节点时,我都会使用一个unordered_map来存储名称和对象指针的映射。

程序 运行 尝试访问 add_child 函数中插入的节点时失败并引发 BAD_ACCESS 异常。最后发现是因为B节点已经被删除了。我的问题是:这会在什么时候发生?

输出为:

add A
add done A
add A
release B
add done A
add B
Exception: EXC_BAD_ACCESS (code=1, address=0x100000010)

当调用push_back类函数时,向量auto-expand/reallocate之后的元素地址会变大space。

一种解决方案是将new分配的地址存储在向量中,并在父节点被解构时将其全部删除。例如

struct Node {
    string name;
    vector<Node*> nodes;
    ~Node() {
        for (auto pch : nodes)
            delete pch;
    }
};

root.nodes.push_back(new Node("child node"));