移动涉及const unique_ptr的构造函数

Move constructor involving const unique_ptr

本文关键字:ptr 构造函数 unique const 移动      更新时间:2023-10-16

在下面的代码中,我将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;
};

move构造函数的语义是矛盾的。

您已经声明了一个const std::unique_ptr,它将(唯一)拥有初始化时使用的值。但是您已经声明了一个移动构造函数,该构造函数应该在构造时将该值移动到另一个对象中。

那么,你认为std::unique_ptr在"临时"中应该发生什么呢?

如果你想让它成为release(),你就违反了它的const性。如果你想让它保持它的值,你就违反了std::unique的约束,CCD_5要求不超过一个这样的对象来拥有任何给定的对象。Checkmate

这个问题揭示了C++语言的一个微妙的局限性。它要求move语义将复制到的作为有效对象。

对于"破坏性移动",有几个非常合理的建议,事实上,这些建议会更好地反映move的大多数用途正在做的事情——从那里"失效"现有的东西。

用谷歌搜索。我还没有做过文献调查,所以不想推荐一个。

您的备选方案是删除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;
}

要了解代码不编译的原因,请反映您是如何声明Foo类的,以及move semantics通常是如何实现的。

声明const unique_ptr<T> p意味着p本身永远不会被修改,但您仍然可以修改指向的对象,因为T不是常量。

move的工作原理与此相反。该功能使用了允许从对象中窃取资源并使其处于空状态的思想(如果空状态有意义的话)。如果有用的话,可以将move视为移动对象的一种"破坏性"副本。

编写std::move(foo.p),基本上就是窃取foo.p指向的资源,并将其保持在安全状态,也就是说将foo.p分配给NULL。但是foo.p被声明为const,因此不允许执行该操作。

请考虑,在您的情况下,您不需要将p声明为const unique_ptr<int>。只需将其声明为unique_ptr<int>,并确保成员函数声明为CCD24,而非成员函数将其作为const unique_ptr<int> p&参数。通过这种方式,您可以确保p在对象生存期内永远不会更改(移动操作除外)。

这是因为unique_ptr只有move构造函数,这意味着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;
};

使用std::unique_ptr的概念表示对象的唯一所有权。您试图实现的是让Foo类拥有一个对象(用std::unique_ptr表示)使其可移动(您的移动构造函数),这会产生矛盾。我会坚持使用std::unique_ptr,或者使用std::shared_ptr进行共享。

您可能想阅读以下内容:聪明的指点者:或者谁拥有你的孩子?

如果要防止所有权转移,可以使用const std::unique_ptr<T>。这不是很有用。

如果要防止修改它所包含的对象,可以使用std::unique_ptr<const T>