复制构造函数以转移 unique_ptr 的所有权
Copy Constructor to transfer ownership of a unique_ptr
我需要编写一个复制构造函数,它还转移被复制对象的 unique_ptr 成员的所有权。情况如下:
class C{
// C class stuff
};
class A{
public:
public A();
public A(const A& a);
private:
std::unique_ptr<C> c_;
}
class B{
public:
B(const A& b) : a_(a){}
private:
A a_;
};
我应该如何实现 A
的复制构造函数?
我猜你的意图或方法是错误的。
复制构造函数旨在创建参数的 copy,但由于 unique_ptr
保持唯一所有权,因此无法复制它。你 可以 实际上使 unique_ptr 成为成员 mutable
然后将它指向的资源移动到复制构造函数中,但这绝对是疯狂的(这就是std::auto_ptr
确实如此,这就是它被弃用的原因)。
因此您需要:
- 向 A 和 B 添加移动构造函数(+ 删除复制构造函数)
- 从
unique_ptr
切换到 shared_ptr
,但前提是确实要共享 C
还有第三种选择,就是复制A的拷贝构造函数中unique_ptr指向的对象,即:
A::A(const A& a) : c_(std::unique_ptr<C>(a.c_ ? new C(*a.c_) : nullptr)) {
}
从技术上讲,
” write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied
你可以这样做:
class Bad
{
private:
unique_ptr<int> p_;
public:
Bad(): p_( new int(666) ) {}
Bad( Bad& other )
: p_( move( other.p_ ) )
{}
};
因为复制构造函数也可以有这个签名,再加上两个,除了更常规的Bad( const Bad& )
。
我把它命名为 class Bad
因为它真的很糟糕,除了破坏别人的代码外,这样做没有任何意义。
而不是不复制的复制构造函数,
实现移动或
的移动构造函数
实现一个复制或
的普通复制构造函数
将 class 设计更改为例如共享所有权.
显然,您不能只对 std::unique_ptr
进行赋值,因为它们的赋值运算符已被删除。这是故意强迫程序员定义他想要的行为。
- 新项目取得
c_
的所有权,使原始项目无效。
- 新物品复制
c_
,保留原物品有效期。
- 新项目共享
c_
的所有权,因此新项目和原始项目都引用同一对象。
在案例 1 中,您正在寻找的是一个移动构造函数,默认的移动构造函数可以正常工作。所以你不需要写任何代码,你可以这样做:
A temp;
A foo(std::move(temp));
注意temp
移动后无效
在情况 2 中,您需要将自定义复制构造函数添加到 A
以创建原件的副本 c_
:
A(const A& a):c_(new C(*(a.c_))){}
在 A
中定义后,您可以:
A foo(A());
请注意,这取决于 C
的复制构造函数的功能。
在情况 3 中,您需要从根本上改变 A
,从使用 std::unique_ptr
到使用 std::shared_ptr
,因此定义c_
将变为:
std::shared_ptr<C> c_;
您对 c_
的构建将与您已经在 std::unique_ptr
版本的 c_
中使用的相同。因此,只需使用默认实现即可:
A foo;
A bar(foo);
现在 foo
和 bar
指向同一个 C
对象,并共享它的所有权。在删除引用它的所有 shared_ptr
之前,不会删除此共享对象。
我需要编写一个复制构造函数,它还转移被复制对象的 unique_ptr 成员的所有权。情况如下:
class C{
// C class stuff
};
class A{
public:
public A();
public A(const A& a);
private:
std::unique_ptr<C> c_;
}
class B{
public:
B(const A& b) : a_(a){}
private:
A a_;
};
我应该如何实现 A
的复制构造函数?
我猜你的意图或方法是错误的。
复制构造函数旨在创建参数的 copy,但由于 unique_ptr
保持唯一所有权,因此无法复制它。你 可以 实际上使 unique_ptr 成为成员 mutable
然后将它指向的资源移动到复制构造函数中,但这绝对是疯狂的(这就是std::auto_ptr
确实如此,这就是它被弃用的原因)。
因此您需要:
- 向 A 和 B 添加移动构造函数(+ 删除复制构造函数)
- 从
unique_ptr
切换到shared_ptr
,但前提是确实要共享 C
还有第三种选择,就是复制A的拷贝构造函数中unique_ptr指向的对象,即:
A::A(const A& a) : c_(std::unique_ptr<C>(a.c_ ? new C(*a.c_) : nullptr)) {
}
从技术上讲,
” write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied
你可以这样做:
class Bad
{
private:
unique_ptr<int> p_;
public:
Bad(): p_( new int(666) ) {}
Bad( Bad& other )
: p_( move( other.p_ ) )
{}
};
因为复制构造函数也可以有这个签名,再加上两个,除了更常规的Bad( const Bad& )
。
我把它命名为 class Bad
因为它真的很糟糕,除了破坏别人的代码外,这样做没有任何意义。
而不是不复制的复制构造函数,
实现移动或
的移动构造函数
实现一个复制或
的普通复制构造函数
将 class 设计更改为例如共享所有权.
显然,您不能只对 std::unique_ptr
进行赋值,因为它们的赋值运算符已被删除。这是故意强迫程序员定义他想要的行为。
- 新项目取得
c_
的所有权,使原始项目无效。 - 新物品复制
c_
,保留原物品有效期。 - 新项目共享
c_
的所有权,因此新项目和原始项目都引用同一对象。
在案例 1 中,您正在寻找的是一个移动构造函数,默认的移动构造函数可以正常工作。所以你不需要写任何代码,你可以这样做:
A temp;
A foo(std::move(temp));
注意temp
移动后无效
在情况 2 中,您需要将自定义复制构造函数添加到 A
以创建原件的副本 c_
:
A(const A& a):c_(new C(*(a.c_))){}
在 A
中定义后,您可以:
A foo(A());
请注意,这取决于 C
的复制构造函数的功能。
在情况 3 中,您需要从根本上改变 A
,从使用 std::unique_ptr
到使用 std::shared_ptr
,因此定义c_
将变为:
std::shared_ptr<C> c_;
您对 c_
的构建将与您已经在 std::unique_ptr
版本的 c_
中使用的相同。因此,只需使用默认实现即可:
A foo;
A bar(foo);
现在 foo
和 bar
指向同一个 C
对象,并共享它的所有权。在删除引用它的所有 shared_ptr
之前,不会删除此共享对象。