使用unique_ptr作为成员时,如何利用编译器生成的拷贝/移动构造函数?
带深拷贝语义的智能指针包装器需求
假设我有一个包含unique_ptr数据成员的类,希望通过深度克隆智能指针指向的对象来让类支持拷贝,示例代码如下:
#include <iostream> #include <memory> using namespace std; class Bar { public: Bar() { cout << "Bar::ctor " << this << '\n'; } ~Bar() { cout << "~Bar" << this << '\n'; } std::unique_ptr<Bar> clone() const { auto p = std::make_unique<Bar>(*this); cout << "Bar::clone() " << this << " to " << p << '\n'; return p; } }; class Foo { public: Foo() = default; ~Foo() = default; Foo(Foo const & other) : p_{other.p_->clone()} { cout << "Foo::copy-ctor " << p_ << ", other.p_ " << other.p_ << '\n'; } Foo(Foo && other) : p_{std::move(other.p_)} { cout << "Foo::move-ctor " << p_ << ", other.p_ " << other.p_ << '\n'; } Foo & operator=(Foo const & other) { cout << "Foo::copy-assign " << p_ << ", other._p " << other.p_ << '\n'; p_ = other.p_->clone(); return *this; } Foo & operator=(Foo && other) { cout << "Foo::move-assign " << p_ << '\n'; p_ = std::move(other.p_); return *this; } void store(std::unique_ptr<Bar> p) { cout << "Foo::store() " << p << '\n'; p_ = std::move(p); } public: // 方便后续打印p_ std::unique_ptr<Bar> p_; }; std::unique_ptr<Bar> bar() { return std::make_unique<Bar>(); } int main() { Foo f; auto b = bar(); cout << "b " << b << '\n'; f.store(std::move(b)); cout << "copy" << '\n'; auto g {f}; cout << "assign" << '\n'; Foo h; h = f; cout << "move" << '\n'; auto i = std::move(f); cout << "f.p_ " << f.p_ << '\n'; cout << "g.p_ " << g.p_ << '\n'; cout << "h.p_ " << h.p_ << '\n'; }
程序输出:
Bar::ctor 0x2314eb0 b 0x2314eb0 Foo::store() 0x2314eb0 copy Bar::clone() 0x2314eb0 to 0x2315ee0 Foo::copy-ctor 0x2315ee0, other.p_ 0x2314eb0 assign Foo::copy-assign 0, other._p 0x2314eb0 Bar::clone() 0x2314eb0 to 0x2315f00 move Foo::move-ctor 0x2314eb0, other.p_ 0 f.p_ 0 g.p_ 0x2315ee0 h.p_ 0x2315f00 ~Bar0x2314eb0 ~Bar0x2315f00 ~Bar0x2315ee0
这段代码的核心问题在于:由于unique_ptr的拷贝构造函数被删除,类无法使用= default;生成默认的拷贝/移动构造函数及赋值运算符,必须手动定义这些函数来实现深拷贝语义。
如果只有单个unique_ptr数据成员,手动定义还不算麻烦,但如果给Foo类添加更多数据成员,就需要在四个拷贝/移动构造函数和赋值运算符中显式地拷贝或赋值这些成员——因为一旦手动定义了其中一个特殊成员函数,编译器就不会再生成其他默认的特殊成员函数了,这会让代码很快变得混乱不堪。
我想知道:标准库中是否存在一种unique_ptr的包装器,既能实现自动深拷贝,又能保持const正确性,从而让Foo类可以简化为如下形式,直接复用编译器生成的默认拷贝/移动构造函数和赋值运算符?
class Foo { public: Foo() = default; ~Foo() = default; Foo(Foo const & other) = default; Foo(Foo && other) = default; Foo & operator=(Foo const & other) = default; Foo & operator=(Foo && other) = default; // ... public: DeepCopyUniquePtr p_; // 这种类型是否存在? int a; float b; // 更多成员... char z; };
内容的提问来源于stack exchange,提问作者davidA
相关产品推荐
相关产品推荐

