当类具有 const std::unique_ptr 类型的成员时,您能否设计一个构造函数以允许“类 c(std::move(another_class))”?

Can you design a constructor to allow `Class c(std::move(another_class))` when the class has a member of type const std::unique_ptr?

提问人:mercury0114 提问时间:1/15/2023 最后编辑:mercury0114 更新时间:1/16/2023 访问量:94

问:

下面是我尝试设计的类的简化版本

class Class {
 public:
     Class(std::unique_ptr<int>&& ptr): ptr_(std::move(ptr)) {}
 private:
     // works only if I change to std::shared_ptr or remove const qualifier
     const std::unique_ptr<int> ptr_;
};

int main() {
  std::unique_ptr<int> ptr = std::make_unique<int>(1);
  Class c(std::move(ptr)); // Compiles
  // I need to construct a new instance d, but c is not needed anymore,
  // anything c owns can be nullified.
  Class d(std::move(c)); // Does not compile
  return 0;
}

由于以下错误消息,我无法从实例构造实例:dc

“Class”的复制构造函数被隐式删除,因为字段“ptr_” 具有已删除的复制构造函数

但是,如果我将成员更改为 类型 ,那么一切正常。ptr_const std::shared_ptr<int>

有没有办法为 ,它支持Class

  • 构造类实例,直接提供它需要的参数
  • 从另一个类实例构造类实例,可能会破坏进程中的另一个实例(即 c(std::move(d));
  • 允许类具有 type 的成员const unique_ptr

?

编辑:使用构建实例也不起作用:dstd::move(c)

class.cc:17:23:错误:使用已删除的函数“Class::Class(Class&&)” 17 |类 d(std::move(c)); |^ class.cc:5:7: 注意: 'Class::Class(Class&&)' 被隐式删除,因为默认的 定义格式不正确:

到目前为止,有两个解决方案对我有用,从可读性的角度来看,两者都不是完美的:

  1. 删除限定符:const

    std::unique_ptr<int> ptr_;

    问题在于,这读作:“调用公共方法时,ptr_成员可能会被修改”

  2. 对共享指针的更改:

    const std::shared_ptr<int> ptr_;

    问题在于,这读作:“我们有多个指针指向相同的数据”

有什么方法可以改进设计,而不会出现(1)和(2)中概述的问题?

C++ 构造函数 move-constructor

评论

2赞 tkausl 1/15/2023
Is there a way to have a single constructor for the Class, which would support:不。
2赞 user17732522 1/15/2023
@mercury0114 告诉意向之后不再需要的规范方法是传递而不是 ,这将导致使用移动构造函数,该构造函数已经隐式定义:。cstd::move(c)cClass d(std::move(c));
4赞 Eljay 1/15/2023
当类具有 const std::unique_ptr 类型的成员时,是否可以设计复制构造函数? 是的,你可以这样做。有没有办法为类使用单个构造函数...? ,您必须自己编写复制构造函数,并考虑编写移动构造函数,并且可能需要/需要复制分配和移动分配。
2赞 user17732522 1/15/2023
"使用 std::move(c) 构造实例 d 也不起作用:“: 是的,很抱歉。我没有注意到你也做了指针。发出指针意味着您打算让它不可能放弃所有权。如果您希望能够转让所有权,那么它一定不是.constconstconst
3赞 Nicol Bolas 1/16/2023
@mercury0114:“const 成员很棒,如果你能做出 const 的东西,你就应该”让成员 const 产生后果。根本无法将对象分配给该对象。这使得与此类类型的交互比需要的要困难得多。

答:

4赞 Nicol Bolas 1/16/2023 #1
  • 从另一个类实例构造类实例,可能会破坏过程中的另一个实例(即c(std::move(d));
  • 允许类具有 type 的成员const unique_ptr

这种欲望的交集本质上是矛盾的。

移动是一种修改操作。如果对象是 ,则无法从中移动。const

其全部目的是程序中有一个实例,它唯一地拥有(并将销毁)它所指向的对象。因此,它不能被复制,因为复制是一个非修改操作。如果可以复制它,那么两个对象将尝试拥有同一个对象。unique_ptr

您不能从 .您不能从任何类型的对象移动。因此,如果对象具有 ,则无法从该对象的其他实例中获取指针。unique_ptrconstconst unique_ptr

通过声明成员为 ,您还声明该对象既不能复制也不能移动。这些是代码选择的后果。const unique_ptr<T>

因此,您将不得不决定什么更重要:成员是或从该对象复制/移动的能力。const

从广义上讲,成员创造的问题比他们通常解决的问题要多。如果成员是私人的,那么这通常就足够了;直接访问该类的用户应该能够知道每个此类函数应该修改什么,不应该修改什么。如果他们犯了一个错误,那么这个错误的代码就会非常有限。const

评论

0赞 mercury0114 1/16/2023
Broadly speaking, const members create more problems than they usually solve- 我不同意这种说法,但其余接受的答案是有道理的,谢谢!