C++17中含多态对象向量的树形结构深拷贝实现问题
C++17多态树形结构深拷贝实现问题
我受限于使用C++17,需要实现一种可深拷贝为两个独立副本的树形结构(不一定是二叉树)。目前定义了抽象基类Node,它有两个派生类:
Operation类:持有布尔操作枚举,以及存储子节点的std::vector<std::unique_ptr<Node>>,作为树的分支节点。Condition类:持有求值用的比较数据,作为树的叶子节点。
另外还有Event类,用std::unique_ptr<Node>指向树的根节点,根节点可以是Operation或Condition类型。
我尝试通过多态clone()方法实现std::unique_ptr的深拷贝,但在Event和Operation的拷贝构造函数里遇到了编译错误,不清楚怎么维持多态性,也不确定这些拷贝构造函数是不是必须写的。
原代码(含编译错误)
#include <algorithm> #include <memory> #include <string> #include <vector> namespace tree { struct Node { // 虚clone函数,返回指向当前对象拷贝的unique_ptr virtual std::unique_ptr<Node> clone() const = 0; std::string name; }; enum class Boolean { And, Or, Xor }; struct Operation : public Node { // 拷贝构造函数:尝试拷贝vector并克隆每个子节点 Operation(const Operation &other) : op(other.op), nodes(other.nodes.size()) { std::transform(other.nodes.cbegin(), other.nodes.cend(), nodes.begin(), [](const auto &old) { // 编译错误:Node是抽象类,无法实例化 return op ? std::make_unique<Node>(old->clone()) : nullptr; }); } virtual std::unique_ptr<Node> clone() const override { return std::make_unique<Operation>(*this); } Boolean op; std::vector<std::unique_ptr<Node>> nodes; }; struct Condition : public Node { virtual std::unique_ptr<Node> clone() const override { return std::make_unique<Condition>(*this); } int datum; }; struct Event { Event(std::string name) : name(name) {} // 编译错误:同样试图实例化抽象类Node Event(const Event &other) : name(other.name), root(std::make_unique<Node>(other.root->clone())) {} std::string name; std::unique_ptr<Node> root; }; } // tree
问题分析与解决方案
错误根源
代码里的编译错误都是因为试图直接实例化抽象基类Node:
std::make_unique<Node>(...)是非法的,因为Node包含纯虚函数,属于抽象类,不能直接创建对象。- 而
clone()方法本身已经返回了一个指向派生类对象的std::unique_ptr<Node>,完全不需要再用make_unique包装。
另外Operation拷贝构造函数里的lambda还存在逻辑错误:用op(布尔操作枚举)作为指针非空的判断条件,这完全是误用,应该判断的是old这个unique_ptr是否为空。
修正后的关键代码
- Operation拷贝构造函数修正
要调用基类拷贝构造函数拷贝name成员,同时正确克隆每个子节点:
Operation(const Operation &other) : Node(other), op(other.op) { std::transform(other.nodes.cbegin(), other.nodes.cend(), std::back_inserter(nodes), [](const auto &old) { return old ? old->clone() : nullptr; }); }
这里用std::back_inserter代替预先分配vector大小,更简洁安全。
- Event拷贝构造函数修正
直接用clone()的返回值初始化root,同时增加空指针判断:
Event(const Event &other) : name(other.name), root(other.root ? other.root->clone() : nullptr) {}
- 补充基类虚析构函数
为了避免多态场景下的内存泄漏,必须给Node添加虚析构函数:
virtual ~Node() = default;
- Condition拷贝构造函数补充
虽然Condition没有复杂成员,但显式调用基类拷贝构造函数是良好的编码习惯:
Condition(const Condition &other) : Node(other), datum(other.datum) {}
拷贝构造函数的必要性
这些拷贝构造函数是必须实现的:
Operation和Event都包含std::unique_ptr,而unique_ptr是不可拷贝的,默认拷贝构造函数会被禁用。- 要实现深拷贝,必须手动调用每个子节点的
clone()方法,确保树形结构的所有节点都被复制为独立对象。
完整修正代码
#include <algorithm> #include <memory> #include <string> #include <vector> namespace tree { struct Node { virtual std::unique_ptr<Node> clone() const = 0; std::string name; // 虚析构函数,确保派生类对象能正确销毁 virtual ~Node() = default; }; enum class Boolean { And, Or, Xor }; struct Operation : public Node { Operation(const Operation &other) : Node(other), op(other.op) { std::transform(other.nodes.cbegin(), other.nodes.cend(), std::back_inserter(nodes), [](const auto &old) { return old ? old->clone() : nullptr; }); } virtual std::unique_ptr<Node> clone() const override { return std::make_unique<Operation>(*this); } Boolean op; std::vector<std::unique_ptr<Node>> nodes; }; struct Condition : public Node { Condition(const Condition &other) : Node(other), datum(other.datum) {} virtual std::unique_ptr<Node> clone() const override { return std::make_unique<Condition>(*this); } int datum; }; struct Event { Event(std::string name) : name(std::move(name)) {} Event(const Event &other) : name(other.name), root(other.root ? other.root->clone() : nullptr) {} std::string name; std::unique_ptr<Node> root; }; } // tree
内容的提问来源于stack exchange,提问作者zecuse
相关产品推荐
相关产品推荐

