[英]Move constructor involving const unique_ptr
In the code below, I made p const because it will never point to any other int during Foo's lifetime.在下面的代码中,我设置了 p const 因为它在 Foo 的生命周期内永远不会指向任何其他 int。 This doesn't compile, as the unique_ptr's copy constructor is called, which is obviously deleted.
这不会编译,因为调用了 unique_ptr 的复制构造函数,这显然被删除了。 Are there any solutions besides making p non-const?
除了使 p 非常量之外,还有其他解决方案吗? Thanks.
谢谢。
#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;
};
The semantics of your move constructor are contradictory.您的移动构造函数的语义是矛盾的。
You have declared a const std::unique_ptr
which will (uniquely) own the value it is initialised with.您已经声明了一个
const std::unique_ptr
,它将(唯一地)拥有它初始化的值。 But you've declared a move constructor that should move that value into another object at construction.但是您已经声明了一个移动构造函数,它应该在构造时将该值移动到另一个对象中。
So what do you think should happen to the std::unique_ptr
in the 'temporary' being move constructed from?那么,您认为构造移动的“临时”中的
std::unique_ptr
应该发生什么?
If you want it to be release()
ed you've violated its const
ness.如果你希望它是
release()
ed,你就违反了它的const
。 If you want it to retain its value you've violated the constraint of std::unique
which requires no more than one such object to own any given object.如果您希望它保留其值,则违反了
std::unique
的约束,该约束要求不超过一个此类对象拥有任何给定对象。 Checkmate.将死。
This problem reveals a subtle limitation of the C++ language.这个问题揭示了 C++ 语言的一个微妙的限制。 It requires
move
semantics to leave the copied to and from as valid objects.它需要
move
语义才能将复制的对象保留为有效对象。
There are several quite reasonable proposals for 'destructive move' which would in truth better reflect what most uses of move
are doing - take a value to here from there 'invalidating' what was there.关于“破坏性移动”有几个相当合理的建议,实际上它们可以更好地反映
move
的大多数用途正在做的事情——从那里“使”那里的东西“无效”。
Google them.谷歌他们。 I haven't made a literature survey so don't want to recommend one.
我没有做过文献调查,所以不想推荐一个。
Your alternatives here are to remove const
or cast it way.您在这里的替代方法是删除
const
或强制转换。 I strongly recommend removing it.我强烈建议删除它。 You can make sure the semantics of your class ensure the appropriate const-ness with no impact and no 'ugly suspect'
const_cast
.您可以确保类的语义确保适当的 const-ness 没有影响,也没有“丑陋的嫌疑人”
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;
}
To understand why your code does not compile, reflect how you have declared Foo
class and how move semantics
is generally implemented.要了解为什么您的代码无法编译,请反映您如何声明
Foo
类以及通常如何实现move semantics
。
Declaring a const unique_ptr<T> p
, you mean that p
itself will be never modified, but you could still modify the pointed-to object because of T
is not const.声明一个
const unique_ptr<T> p
,你的意思是p
本身永远不会被修改,但你仍然可以修改指向的对象,因为T
不是 const。
But move
works on an opposite assumption.但是
move
在相反的假设上起作用。 This feature uses the idea that is allowed stealing resources from objects and leave them in a empty state (if an empty state make sense).此功能使用允许从对象中窃取资源并将它们保持在空状态(如果空状态有意义)的想法。 If can be useful, think
move
as a sort of 'destructive' copy for the moved object.如果可能有用,
move
视为移动对象的一种“破坏性”副本。
Writing std::move(foo.p)
, basically you steal the resource pointed by foo.p
and leave it in a safe state, that means assign foo.p
to NULL
.编写
std::move(foo.p)
,基本上你窃取了foo.p
指向的资源并将其置于安全状态,这意味着将foo.p
分配给NULL
。 But foo.p
was declared as const, so the operation is not permitted.但是
foo.p
被声明为 const,因此不允许该操作。
Please consider that in your case you don't need to declare p as a const unique_ptr<int>
.请考虑,在您的情况下,您不需要将 p 声明为
const unique_ptr<int>
。 Simply declare it as unique_ptr<int>
and make sure that member functions are declared as const
and non-member functions take it as const unique_ptr<int> p&
parameter.只需将其声明为
unique_ptr<int>
并确保将成员函数声明为const
而非成员函数将其作为const unique_ptr<int> p&
参数。 In this way you are sure that p
will never change along the object lifetime (except in case of move operation).通过这种方式,您可以确定
p
在对象生命周期内永远不会改变(移动操作除外)。
It is because unique_ptr
has only the move-constructor, which means the initialization argument to p
cannot be const, while p
is const.这是因为
unique_ptr
只有 move-constructor,这意味着p
的初始化参数不能是 const,而p
是 const。 I think what you wanted was to declare我想你想要的是声明
unique_ptr p;
unique_ptr p;
instead of代替
const unique_ptr p;
常量 unique_ptr p;
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;
};
Concept of using std::unique_ptr is representing a sole ownership of an object.使用 std::unique_ptr 的概念表示对象的唯一所有权。 What you're trying to achieve is having a Foo class own an object (which is expressed by std::unique_ptr) and making it movable (your move constructor) which makes a contradiction.
您想要实现的是让 Foo 类拥有一个对象(由 std::unique_ptr 表示)并使其可移动(您的移动构造函数),这会产生矛盾。 I would stick with std::unique_ptr or make it shared using std::shared_ptr.
我会坚持使用 std::unique_ptr 或使用 std::shared_ptr 共享它。
You might want to read this: Smart Pointers: Or who owns you baby?您可能想阅读以下内容: 智能指针:或者谁拥有您的宝贝?
If you want to prevent transfer of ownership, you can use a const std::unique_ptr<T>
.如果要防止所有权转移,可以使用
const std::unique_ptr<T>
。 This is not very useful.这不是很有用。
If you want to prevent modifying the object it holds, you can use a std::unique_ptr<const T>
.如果你想防止修改它持有的对象,你可以使用
std::unique_ptr<const T>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.