代码之家  ›  专栏  ›  技术社区  ›  Muhammad Rehan Saeed

C++移动语义与智能指针相关的复制构造函数和赋值运算符

  •  1
  • Muhammad Rehan Saeed  · 技术社区  · 10 年前

    我试图找出何时使用移动语义,以及何时使用复制构造函数和赋值运算符作为经验法则。你在课堂上使用的指针类型(如果有的话)似乎会受到这个答案的影响,所以我把它包括在内。

    无指针 -基于 this 答案是,如果您有一个具有int和string等基本类型的POD类,则不需要编写自定义的移动或复制构造函数和运算符。

    唯一ptr -基于 this 答案是,当使用移动语义时,uniqueptr比sharedptr更适合,因为资源只能有一个uniquepter。

    共享ptr -同样,如果使用复制语义,shared_ptr似乎是可行的。对象可以有多个副本,因此拥有一个指向资源的共享指针对我来说是有意义的。但是,unique_ptr通常比shared_ptr更受欢迎,因此如果可以,请避免使用此选项。

    但是:

    1. 我什么时候应该使用移动语义?
    2. 我什么时候应该使用复制语义?
    3. 我应该同时使用吗?
    4. 我是否应该使用none并依赖默认的复制构造函数和赋值运算符?
    2 回复  |  直到 7 年前
        1
  •  6
  •   Nicolas Louis Guillemot    10 年前

    如名称所示,使用 unique_ptr 当资源必须正好有一个所有者时。的复制构造函数 唯一_ptr 已禁用,这意味着它的两个实例不可能存在。然而,它是可移动的。。。这很好,因为这允许所有权转移。

    同样如名称所示, shared_ptr 表示资源的共享所有权。然而,两个智能指针之间还有另一个区别: Deleter 唯一_ptr 是其类型签名的一部分,但不是 共享ptr 。那是因为 共享ptr 使用“类型擦除”来“擦除删除器的类型”。还要注意 共享ptr 也可以移动以转移所有权(如 唯一_ptr .)

    我什么时候应该使用移动语义?

    虽然 共享ptr 可以复制,在进行所有权转移时(与创建新引用相反),您可能希望以任何方式移动它们。您有义务使用移动语义 唯一_ptr ,因为所有权必须是唯一的。

    我什么时候应该使用复制语义?

    对于智能指针,应使用复制来增加 共享ptr s.(如果您不熟悉引用计数的概念,请研究引用计数的垃圾收集。)

    我应该同时使用吗?

    对如上所述, 共享ptr 可以复制和移动。复制表示增加引用计数,而移动仅表示所有权转移(引用计数保持不变)

    我是否应该使用none并依赖默认的复制构造函数和赋值运算符?

    当您希望逐成员复制对象时。

        2
  •  5
  •   Joseph Mansfield    10 年前
    1. 我什么时候应该使用移动语义?

      我想你的意思是,“我什么时候应该给我的类一个移动构造函数?”答案是每当移动这种类型的对象是有用的,而默认的移动构造函数不能正确完成任务时。当资源从一个对象转移到另一个对象时,移动是有用的。例如,移动对 std::string 因为它允许从临时库复制对象,而不必重新分配和复制它们的内部资源,而是简单地将资源从一个移动到另一个。许多类型将从中受益。另一方面,移动对 std::unique_ptr 因为这是通过 标准::unique_ptr 在不违反其“独特所有权”的情况下,以价值为导向。

    2. 我什么时候应该使用复制语义?

      同样,我认为你的意思是,“我什么时候应该给我的类一个复制构造函数?”每当你需要能够复制一个对象时,在它们之间复制内部资源,而默认的复制构造函数不能正确完成这项工作。复制几乎对任何类型都有用,除了以下类型 标准::unique_ptr 必须对内部资源强制执行唯一所有权。

    3. 我应该同时使用吗?

      您的类应该在大多数时候同时提供复制和移动语义。最常见的类应该是可复制的和可移动的。可复制提供了按值传递对象的标准语义。可移动允许在通过临时对象时按值进行优化。这是否意味着必须提供复制或移动构造函数取决于默认构造函数是否执行了适当的操作。

    4. 我是否应该使用none并依赖默认的复制构造函数和赋值运算符?

      默认的copy和move构造函数只是分别复制或移动类的每个成员。如果这种行为适合复制和移动你的班级,那就太好了。大多数时候,这应该足够好了。例如,如果我有一个包含 std::字符串 ,默认的复制构造函数将复制字符串,而默认的移动构造函数将将字符串的资源移动到新对象-两者都执行相应的工作。如果您的类包含 标准::unique_ptr ,复制根本不起作用,您的类只能移动。这可能是您想要的,或者您可能想要实现一个执行资源深度复制的复制构造函数。当类本身执行资源管理(使用 new delete 例如)。如果是这样的话,默认构造函数几乎永远不会很好地管理这些资源。

    这里的一切同样适用于赋值运算符。