移动涉及 const unique_ptr 的构造函数
Move constructor involving const unique_ptr
在下面的代码中,我将 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;
};
如果要防止所有权转移,可以使用const std::unique_ptr<T>
。这个用处不大。
如果你想防止修改它持有的对象,你可以使用std::unique_ptr<const T>
.
使用 std::unique_ptr 的概念表示对象的唯一所有权。你想要实现的是让 Foo class 拥有一个对象(由 std::unique_ptr 表示) 和 使其可移动(你的移动构造函数)这造成矛盾。我会坚持使用 std::unique_ptr 或使用 std::shared_ptr.
共享它
您可能想阅读以下内容:
Smart Pointers: Or who owns you baby?
你的移动构造函数的语义是矛盾的。
您已经声明了一个 const std::unique_ptr
它将(唯一地)拥有它被初始化的值。
但是您已经声明了一个移动构造函数,它应该在构造时将该值移动到另一个对象中。
那么你认为 'temporary' 中的 std::unique_ptr
应该怎么处理?
如果您想要release()
编辑它,您就违反了它的const
性。
如果你想让它保留它的价值,你就违反了 std::unique
的约束,只需要一个这样的对象就可以拥有任何给定的对象。
将死。
这个问题揭示了 C++ 语言的一个微妙的局限性。它需要 move
语义才能将复制到 和 的内容作为有效对象。
'destructive move' 有几个非常合理的建议,实际上可以更好地反映 move
的大多数用途 - 从那里取值 'invalidating' 那里有什么.
Google 他们。我没有做过文献调查,所以不想推荐。
您的替代方案是删除 const
或强制转换。
我强烈建议删除它。您可以确保 class 的语义确保适当的 const-ness 没有影响,也没有 'ugly suspect' 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;
}
要了解为什么您的代码无法编译,请反映您是如何声明 Foo
class 以及 move semantics
通常是如何实现的。
声明一个 const unique_ptr<T> p
,你的意思是 p
本身永远不会被修改,但是你仍然可以修改指向的对象,因为 T
不是常量。
但是 move
基于相反的假设。此功能使用允许从对象窃取资源并使它们处于空状态(如果空状态有意义)的想法。如果有用,请将 move
视为移动对象的一种 'destructive' 副本。
写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
永远不会随着对象的生命周期而改变(移动操作除外)。
因为unique_ptr
只有移动构造函数,也就是说p
的初始化参数不能是const,而p
是const。我想你想要的是声明
unique_ptr p;
而不是
const 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;
};
在下面的代码中,我将 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;
};
如果要防止所有权转移,可以使用const std::unique_ptr<T>
。这个用处不大。
如果你想防止修改它持有的对象,你可以使用std::unique_ptr<const T>
.
使用 std::unique_ptr 的概念表示对象的唯一所有权。你想要实现的是让 Foo class 拥有一个对象(由 std::unique_ptr 表示) 和 使其可移动(你的移动构造函数)这造成矛盾。我会坚持使用 std::unique_ptr 或使用 std::shared_ptr.
共享它您可能想阅读以下内容: Smart Pointers: Or who owns you baby?
你的移动构造函数的语义是矛盾的。
您已经声明了一个 const std::unique_ptr
它将(唯一地)拥有它被初始化的值。
但是您已经声明了一个移动构造函数,它应该在构造时将该值移动到另一个对象中。
那么你认为 'temporary' 中的 std::unique_ptr
应该怎么处理?
如果您想要release()
编辑它,您就违反了它的const
性。
如果你想让它保留它的价值,你就违反了 std::unique
的约束,只需要一个这样的对象就可以拥有任何给定的对象。
将死。
这个问题揭示了 C++ 语言的一个微妙的局限性。它需要 move
语义才能将复制到 和 的内容作为有效对象。
'destructive move' 有几个非常合理的建议,实际上可以更好地反映 move
的大多数用途 - 从那里取值 'invalidating' 那里有什么.
Google 他们。我没有做过文献调查,所以不想推荐。
您的替代方案是删除 const
或强制转换。
我强烈建议删除它。您可以确保 class 的语义确保适当的 const-ness 没有影响,也没有 'ugly suspect' 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;
}
要了解为什么您的代码无法编译,请反映您是如何声明 Foo
class 以及 move semantics
通常是如何实现的。
声明一个 const unique_ptr<T> p
,你的意思是 p
本身永远不会被修改,但是你仍然可以修改指向的对象,因为 T
不是常量。
但是 move
基于相反的假设。此功能使用允许从对象窃取资源并使它们处于空状态(如果空状态有意义)的想法。如果有用,请将 move
视为移动对象的一种 'destructive' 副本。
写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
永远不会随着对象的生命周期而改变(移动操作除外)。
因为unique_ptr
只有移动构造函数,也就是说p
的初始化参数不能是const,而p
是const。我想你想要的是声明
unique_ptr p;
而不是
const 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;
};