我编写了以下代码,尝试将unique_ptr
对象的值复制到结构中。
#include <iostream>
#include <memory>
using namespace std;
struct S {
S(int X = 0, int Y = 0):x(X), y(Y){}
// S(const S&) {}
// S& operator=(const S&) { return *this; }
int x;
int y;
std::unique_ptr<S> ptr;
};
int main() {
S s;
s.ptr = std::unique_ptr<S>(new S(1, 4));
S p = *s.ptr; // Copy the pointer's value
return 0;
}
它在Visual C ++ 2012中弹出错误:
IntelliSense:没有合适的用户定义从“S”到“S”的转换 存在
中声明的私有成员
IntelliSense:没有运算符“=”匹配这些操作数 操作数类型是:std :: unique_ptr&gt; = std :: unique_ptr&gt;
错误C2248:'std :: unique_ptr&lt; _Ty&gt; :: unique_ptr':无法访问 在类'std :: unique_ptr&lt; _Ty&gt;'
除非我取消注释我尝试定义复制构造函数和=运算符的行。 这消除了编译器错误,但没有消除IntelliSense错误。无论错误列表中显示的IntelliSense错误如何,它都会编译。
那么,为什么它不能只使用默认函数并用它们编译?我是以正确的方式做价值的副本吗?如果需要复制构造函数,我该如何定义?
答案 0 :(得分:6)
复制构造函数不会隐式生成,因为您有一个用户定义的构造函数,为什么复制S
的尝试失败的原因。
但仍然unique_ptr
不可复制,只有可移动,因此您可以使用移动构造函数来S
:
S(S&& other) : x(other.x), y(other.y), ptr(std::move(other.ptr))
{
}
并称之为:
S p = std::move(s); // Move s to p
答案 1 :(得分:2)
std::unique_ptr
既不是Copy Constructible也不是Copy Assignable。
S
的隐式副本赋值运算符和构造函数将生成错误,因此会显示错误消息。
然而,您可以使用S p = std::move(s);
,因为std::unique_ptr
是移动可构建和移动可分配,
答案 2 :(得分:2)
那么,为什么它不能只使用默认函数并用它们编译?
据我了解,unique_ptr
容器背后的想法是它只处理其内容的生命(指向T
),直到从该职责中解除(使用{{1或者swap
方法),或者有效地破坏了它的内容(当它本身被破坏时)。 reset
的第二个重要属性是它必须允许unique_ptr
的不完整类型(以便支持不透明指针)。这意味着包含的值可能不是 CopyConstructible 。因此,T
本身不能被允许为 CopyConstructible 。
我是否以正确的方式复制价值? 如果需要复制构造函数,我该如何定义?
如果unique_ptr
最终成为 CopyConstructible ,那么您必须手动处理副本,方法是访问指针,就像在{{1 }}。复制构造函数应该做同样的事情。
答案 3 :(得分:2)
不是一个完整的答案,只是提供信息:
我强烈建议您在实验中添加可见性:
std::ostream&
operator<<(std::ostream& os, const S& s)
{
os << '{' << s.x << ", " << s.y << ", ";
if (s.ptr != nullptr)
os << s.ptr.get() << ':' << *s.ptr;
else
os << "nullptr";
return os << '}';
}
现在你可以这样说:
cout << "s = " << s << '\n';
在实验的多个地方,真正了解每个步骤后发生的事情。这可以帮助您分析并继续设计。