如何将 unique_ptr 参数传递给构造函数或函数? [英] How do I pass a unique_ptr argument to a constructor or a function?

查看:59
本文介绍了如何将 unique_ptr 参数传递给构造函数或函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm new to move semantics in C++11 and I don't know very well how to handle unique_ptr parameters in constructors or functions. Consider this class referencing itself:

#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 参数的函数吗?

Is this how I should write functions taking unique_ptr arguments?

我需要在调用代码中使用 std::move 吗?

And do I need to use std::move in the calling code?

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

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

推荐答案

以下是将唯一指针作为参数的可能方法,以及它们的相关含义.

Here are the possible ways to take a unique pointer as an argument, as well as their associated meaning.

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

为了让用户调用它,他们必须执行以下操作之一:

In order for the user to call this, they must do one of the following:

Base newBase(std::move(nextBase));
Base fromTemp(std::unique_ptr<Base>(new Base(...));

按值获取唯一指针意味着您正在转让指向相关函数/对象/等的指针的所有权.newBase 构造完成后,nextBase 保证为.您不拥有该对象,您甚至不再拥有指向它的指针.没了.

To take a unique pointer by value means that you are transferring ownership of the pointer to the function/object/etc in question. After newBase is constructed, nextBase is guaranteed to be empty. You don't own the object, and you don't even have a pointer to it anymore. It's gone.

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

This is ensured because we take the parameter by value. std::move doesn't actually move anything; it's just a fancy cast. std::move(nextBase) returns a Base&& that is an r-value reference to nextBase. That's all it does.

因为 Base::Base(std::unique_ptr<Base> n) 通过值而不是 r 值引用来获取它的参数,C++ 会自动为我们构造一个临时变量.它从我们通过 std::move(nextBase) 给函数的 Base&& 创建了一个 std::unique_ptr.正是这个临时文件的构造实际上值从 nextBase 移动到函数参数 n 中.

Because Base::Base(std::unique_ptr<Base> n) takes its argument by value rather than by r-value reference, C++ will automatically construct a temporary for us. It creates a std::unique_ptr<Base> from the Base&& that we gave the function via std::move(nextBase). It is the construction of this temporary that actually moves the value from nextBase into the function argument n.

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

这必须在实际的左值(命名变量)上调用.它不能用这样的临时调用:

This has to be called on an actual l-value (a named variable). It cannot be called with a temporary like this:

Base newBase(std::unique_ptr<Base>(new Base)); //Illegal in this case.

this 的含义与任何其他使用非常量引用的含义相同:函数可以或不声明指针的所有权.鉴于此代码:

The meaning of this is the same as the meaning of any other use of non-const references: the function may or may not claim ownership of the pointer. Given this code:

Base newBase(nextBase);

不能保证 nextBase 为空.它可能为空;可能不会.这实际上取决于 Base::Base(std::unique_ptr &n) 想要做什么.正因为如此,仅仅从函数签名中不太清楚会发生什么;您必须阅读实现(或相关文档).

There is no guarantee that nextBase is empty. It may be empty; it may not. It really depends on what Base::Base(std::unique_ptr<Base> &n) wants to do. Because of that, it's not very evident just from the function signature what's going to happen; you have to read the implementation (or associated documentation).

因此,我不建议将此作为界面.

Because of that, I wouldn't suggest this as an interface.

Base(std::unique_ptr<Base> const &n);

我没有展示实现,因为你不能const&移动.通过传递 const&,您是说该函数可以通过指针访问 Base,但它不能将它存储到任何地方.它不能声明其所有权.

I don't show an implementation, because you cannot move from a const&. By passing a const&, you are saying that the function can access the Base via the pointer, but it cannot store it anywhere. It cannot claim ownership of it.

这很有用.不一定适用于您的特定情况,但是能够将指针交给某人并且知道他们不能总是好的(不违反 C++ 规则,例如不丢弃 const) 声称拥有它.他们不能储存它.他们可以把它传给别人,但其他人必须遵守同样的规则.

This can be useful. Not necessarily for your specific case, but it's always good to be able to hand someone a pointer and know that they cannot (without breaking rules of C++, like no casting away const) claim ownership of it. They can't store it. They can pass it to others, but those others have to abide by the same rules.

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

这或多或少与by non-const l-value reference"情况相同.区别在于两点.

This is more or less identical to the "by non-const l-value reference" case. The differences are two things.

  1. 可以传递一个临时的:

Base newBase(std::unique_ptr<Base>(new Base)); //legal now..

  • 必须在传递非临时参数时使用std::move.

  • You must use std::move when passing non-temporary arguments.

    后者才是真正的问题.如果您看到这一行:

    The latter is really the problem. If you see this line:

    Base newBase(std::move(nextBase));
    

    您有一个合理的期望,在此行完成后,nextBase 应该是空的.它应该被移出.毕竟,您让 std::move 坐在那里,告诉您发生了移动.

    You have a reasonable expectation that, after this line completes, nextBase should be empty. It should have been moved from. After all, you have that std::move sitting there, telling you that movement has occurred.

    问题是它没有.不保证已被移出.它可能已被移出,但您只能通过查看源代码才能知道.您不能仅从函数签名中判断.

    The problem is that it hasn't. It is not guaranteed to have been moved from. It may have been moved from, but you will only know by looking at the source code. You cannot tell just from the function signature.

    • (A) 按值:如果您的意思是让函数声明unique_ptr所有权,请按值获取.莉>
    • (C) 通过 const l 值引用: 如果您的意思是让函数在该函数执行期间仅使用 unique_ptr,请通过 <代码>常量和.或者,将 &const& 传递给指向的实际类型,而不是使用 unique_ptr.
    • (D) 通过 r 值引用: 如果一个函数可能会或可能不会声明所有权(取决于内部代码路径),则通过 &&.但我强烈建议您尽可能不要这样做.
    • (A) By Value: If you mean for a function to claim ownership of a unique_ptr, take it by value.
    • (C) By const l-value reference: If you mean for a function to simply use the unique_ptr for the duration of that function's execution, take it by const&. Alternatively, pass a & or const& to the actual type pointed to, rather than using a unique_ptr.
    • (D) By r-value reference: If a function may or may not claim ownership (depending on internal code paths), then take it by &&. But I strongly advise against doing this whenever possible.

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

    You cannot copy a unique_ptr. You can only move it. The proper way to do this is with the std::move standard library function.

    如果您按值获取 unique_ptr,则可以自由移动.但是由于std::move,移动实际上并没有发生.采取以下声明:

    If you take a unique_ptr by value, you can move from it freely. But movement doesn't actually happen because of std::move. Take the following statement:

    std::unique_ptr<Base> newPtr(std::move(oldPtr));
    

    这实际上是两个陈述:

    std::unique_ptr<Base> &&temporary = std::move(oldPtr);
    std::unique_ptr<Base> newPtr(temporary);
    

    (注意:上面的代码在技术上不能编译,因为非临时 r 值引用实际上不是 r 值.它在这里仅用于演示目的).

    (note: The above code does not technically compile, since non-temporary r-value references are not actually r-values. It is here for demo purposes only).

    temporary 只是对 oldPtr 的 r 值引用.它在 newPtr构造函数 中发生移动.unique_ptr 的移动构造函数(一个将 && 用于自身的构造函数)才是实际的移动.

    The temporary is just an r-value reference to oldPtr. It is in the constructor of newPtr where the movement happens. unique_ptr's move constructor (a constructor that takes a && to itself) is what does the actual movement.

    如果你有一个 unique_ptr 值并且你想把它存储在某个地方,你必须使用 std::move 来做存储.

    If you have a unique_ptr value and you want to store it somewhere, you must use std::move to do the storage.

    这篇关于如何将 unique_ptr 参数传递给构造函数或函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆