使用auto与std::vector构建递归结构时对象过早销毁问题
树形结构子节点过早销毁无法显示的原因及解决
我在实现树形结构时编写了如下代码:
#include <iostream> #include <string> #include <string_view> #include <vector> struct Node { std::string _name; std::vector<Node> _subnodes; Node(const std::string_view sv) : _name(sv), _subnodes() { //std::cout << "construct '" << _name << "'" << std::endl; } ~Node() { //std::cout << "destruct '" << _name << "'" << std::endl; } Node& add(const std::string_view sv) { return _subnodes.emplace_back(sv); } void dump(size_t indent=0) const { for (size_t i=0; i<indent; i++) { std::cout << " "; } std::cout << _name << std::endl; for (const auto& n : _subnodes) { n.dump(indent+1); } } }; int main() { auto root = Node("root"); auto alpha = root.add("alpha"); alpha.add("one"); alpha.add("two"); alpha.add("three"); auto beta = root.add("beta"); beta.add("four"); beta.add("five"); beta.add("six"); auto gamma = root.add("gamma"); gamma.add("seven"); gamma.add("eight"); gamma.add("nine"); root.dump(); return 0; }
不知为何,子节点“one”至“nine”过早销毁,无法在dump输出中显示。该现象似乎不依赖于所使用的编译器,请问这是什么原因?
问题原因
核心问题出在变量声明时未使用引用:
add函数返回的是Node&(容器中新添加节点的引用),但你用auto alpha = root.add("alpha");声明变量时,auto会推导为Node而非Node&,这会触发拷贝构造,生成一个alpha的局部副本。后续调用alpha.add("one")等操作,都是在这个副本上添加子节点,而非修改root容器中实际存储的alpha节点。
当这个局部副本的生命周期结束(比如执行到下一行声明beta时),它会被销毁,其包含的子节点(one、two、three)也会随之销毁。而root里的alpha节点自始至终都没有子节点,所以dump时自然看不到这些子节点。
解决方法
将alpha、beta、gamma的声明改为引用类型,在auto后添加&:
auto& alpha = root.add("alpha"); auto& beta = root.add("beta"); auto& gamma = root.add("gamma");
这样变量会直接绑定到root容器内的节点上,后续添加子节点的操作都会作用于真实存储的节点,不会产生临时副本,子节点也就不会被提前销毁,dump时就能正常显示所有层级的节点了。
内容的提问来源于stack exchange,提问作者md2perpe
相关产品推荐
相关产品推荐

