gpt4 book ai didi

c++ - 如何将unique_ptr参数传递给构造函数或函数?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:44:00 26 4
gpt4 key购买 nike

我是C++ 11中移动语义的新手,而且我不太清楚如何处理构造函数或函数中的unique_ptr参数。考虑此类本身的引用:

#include <memory>

class Base
{
public:

typedef unique_ptr<Base> UPtr;

Base(){}
Base(Base::UPtr n):next(std::move(n)){}

virtual ~Base(){}

void setNext(Base::UPtr n)
{
next = std::move(n);
}

protected :

Base::UPtr next;

};

这是我应该如何编写带有 unique_ptr参数的函数吗?

我是否需要在调用代码中使用 std::move

Base::UPtr b1;
Base::UPtr b2(new Base());

b1->setNext(b2); //should I write b1->setNext(std::move(b2)); instead?

最佳答案

以下是将唯一指针作为自变量及其相关含义的可能方法。

(A)按值(value)

Base(std::unique_ptr<Base> n)
: next(std::move(n)) {}

为了使用户能够调用它,他们必须执行以下操作之一:
Base newBase(std::move(nextBase));
Base fromTemp(std::unique_ptr<Base>(new Base(...));

按值获取唯一的指针意味着您正在将指针的所有权转让给所涉及的函数/对象/等。构造 newBase后,保证 nextBase为空。您不拥有该对象,甚至不再有指向它的指针。它消失了。

这是可以确保的,因为我们按值取参数。 std::move实际上并没有移动任何东西。这只是一个花哨的 Actor 。 std::move(nextBase)返回 Base&&,它是对 nextBase的r值引用。这就是全部。

因为 Base::Base(std::unique_ptr<Base> n)接受值而不是r值引用,所以C++会自动为我们构造一个临时变量。它根据我们通过 std::unique_ptr<Base>提供的功能的 Base&&创建一个 std::move(nextBase)。正是这个临时结构的构造实际上将值从 nextBase移到了函数参数 n中。

(B)通过非常量L值引用
Base(std::unique_ptr<Base> &n)
: next(std::move(n)) {}

必须在实际的L值(命名变量)上调用它。不能用这样的临时调用:
Base newBase(std::unique_ptr<Base>(new Base)); //Illegal in this case.

其含义与非常量引用的任何其他用法相同:该函数可以声明也可以不声明指针的所有权。给出以下代码:
Base newBase(nextBase);

不能保证 nextBase为空。它可能是空的;可能不会。这实际上取决于 Base::Base(std::unique_ptr<Base> &n)想要做什么。因此,仅从函数签名中就不会很明显了。您必须阅读实现(或相关文档)。

因此,我不建议将此作为接口(interface)。

(C)通过const l值引用
Base(std::unique_ptr<Base> const &n);

我没有显示实现,因为您不能从 const&移出。通过传递 const&,您说的是该函数可以通过指针访问 Base,但无法将其存储在任何地方。它不能要求它的所有权。

这可能很有用。不一定要针对您的特定情况,但是能够向某人提供一个指针并知道他们不能(没有破坏C++的规则,就像不抛弃 const一样)声明对它的所有权总是一件好事。他们无法存储它。他们可以将其传递给其他人,但是其他人必须遵守相同的规则。

(D)按r值引用
Base(std::unique_ptr<Base> &&n)
: next(std::move(n)) {}

这或多或少与“通过非常量l值引用”情况相同。区别是两件事。
  • 您可以通过一个临时的:
    Base newBase(std::unique_ptr<Base>(new Base)); //legal now..
  • 传递非临时参数时,必须使用std::move

  • 后者确实是问题。如果看到此行:
    Base newBase(std::move(nextBase));

    您有合理的期望,在这一行完成之后, nextBase应该为空。它应该已经从。毕竟,您坐在那里有 std::move,告诉您发生了移动。

    问题在于它还没有。不保证已将其从中移出。它可能已经被移走了,但是您只有通过查看源代码才能知道。您不能仅从函数签名中分辨出来。

    推荐建议
  • (A)按值:如果您要使用某个函数声明对unique_ptr的所有权,请按值取值。
  • (C)通过const l值引用:如果您想让函数在该函数执行期间仅使用unique_ptr,请使用const&。或者,将&const&传递给所指向的实际类型,而不是使用unique_ptr
  • (D)通过r值引用:如果一个函数可能或可能不主张所有权(取决于内部代码路径),则使用&&对其进行取用。但是我强烈建议不要在可能的情况下这样做。

  • 如何操作unique_ptr

    您不能复制 unique_ptr。您只能移动它。正确的方法是使用 std::move标准库函数。

    如果按值获取 unique_ptr,则可以自由移动它。但是由于 std::move,移动实际上并没有发生。采取以下声明:
    std::unique_ptr<Base> newPtr(std::move(oldPtr));

    这实际上是两个声明:
    std::unique_ptr<Base> &&temporary = std::move(oldPtr);
    std::unique_ptr<Base> newPtr(temporary);

    (注意:由于非临时r值引用实际上不是r值,因此上述代码在技术上无法编译。此处仅用于演示目的)。
    temporary只是对 oldPtr的r值引用。移动发生在 newPtr的构造函数中。 unique_ptr的move构造函数(将 &&本身带给自己的构造函数)是实际的 Action 。

    如果您具有 unique_ptr值,并且想要将其存储在某个位置,则必须使用 std::move进行存储。

    关于c++ - 如何将unique_ptr参数传递给构造函数或函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42941859/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com