在下面的代码中,我创建了p const,因为在Foo的生命周期中它永远不会指向任何其他int。这不会编译,因为调用了unique_ptr的复制构造函数,这显然已被删除。除了使p非常数之外还有其他解决方案吗?感谢。
#include <memory>
using namespace std;
class Foo
{
public:
//x is a large struct in reality
Foo(const int* const x) : p(x) {};
Foo(Foo&& foo) : p(std::move(foo.p)) {};
private:
const unique_ptr<int> p;
};
答案 0 :(得分:5)
移动构造函数的语义是矛盾的。
您已声明const std::unique_ptr
将(唯一)拥有初始化的值。
但是你已经宣布了一个移动构造函数,它应该将该值移动到构造中的另一个对象。
那么您认为临时&#39;中的std::unique_ptr
会发生什么?从...构建移动
如果您希望它release()
,则您违反了const
。
如果您希望它保留其值,则您违反了std::unique
的约束,只需要一个这样的对象来拥有任何给定的对象。
的将死。强>
这个问题揭示了C ++语言的一个微妙限制。它需要move
语义才能将复制到和作为有效对象。
对于“破坏性移动”有几个非常合理的建议。这实际上更好地反映了move
的大多数用途正在做什么 - 从那里获取价值&#39;无效&#39;什么在那里。
此处的替代方法是删除const
或将其删除。
我强烈建议删除它。你可以确保你班级的语义确保适当的持久性,没有任何影响,也没有“丑陋的怀疑”。 const_cast
。
#include <iostream>
#include <memory>
class Foo
{
public:
Foo(const int x) : p(new int(x)) {};
Foo(Foo&& foo) :
p(std::move(foo.p)) {
};
int get(void)const{
return *(this->p);
}
private:
std::unique_ptr<int> p;
};
Foo getMove(){
return Foo(88);
}
int main(){
Foo bar(getMove());
std::cout<<bar.get()<<std::endl;
return EXIT_SUCCESS;
}
答案 1 :(得分:2)
要理解您的代码无法编译的原因,请反映您已宣布Foo
类的方式以及通常如何实现move semantics
。
声明const unique_ptr<T> p
,你的意思是p
本身永远不会被修改,但你仍然可以修改指向对象,因为T
不是const。
但move
的作用相反。此功能使用允许从对象窃取资源并将其保留为空状态的想法(如果空状态有意义)。如果可能有用,请将move
视为一种“破坏性”&#39;复制移动的对象。
写std::move(foo.p)
,基本上你窃取foo.p
指向的资源并将其保持在安全状态,这意味着将foo.p
分配给NULL
。但foo.p
被声明为const,因此不允许进行操作。
请注意,在您的情况下,您不需要将p声明为const unique_ptr<int>
。只需将其声明为unique_ptr<int>
并确保成员函数声明为const
,非成员函数将其视为const unique_ptr<int> p&
p
参数。通过这种方式,您可以确保{{1}}永远不会沿对象生命周期发生变化(移动操作除外)。
答案 2 :(得分:1)
使用std :: unique_ptr的概念表示对象的唯一所有权。你要实现的是让Foo类拥有一个对象(由std :: unique_ptr表示)和使它成为可移动的(你的移动构造函数),这会产生矛盾。我会坚持使用std :: unique_ptr或使用std :: shared_ptr进行共享。
答案 3 :(得分:1)
这是因为int lastCol = r.Column;
只有move-constructor,这意味着unique_ptr
的初始化参数不能是const,而p
是const。我想你想要的是宣布
unique_ptr p;
而不是
const unique_ptr p;
p
答案 4 :(得分:0)
如果您想阻止所有权转让,可以使用const std::unique_ptr<T>
。这不是很有用。
如果您想阻止修改它所拥有的对象,可以使用std::unique_ptr<const T>
。