将std::unique_ptr传递给构造函数以接管所有权

5

我希望将一个std::unique_ptr传递给一个类的构造函数,该类将拥有由std::unique_ptr拥有的数据。

在编译器处理它们的方式上,下面的方法foobar之间是否有任何区别,这使得其中一个更可取?

foo类:

template <class T>
class foo
{
    std::unique_ptr<T> data_;

public:
    foo(std::unique_ptr<T>&& data) :
        data_{ std::forward<std::unique_ptr<T>>(data) }
    {
    }
};

bar类:

template <class T>
class bar
{
    std::unique_ptr<T> data_;

public:
    bar(std::unique_ptr<T> data) :
        data_{ std::move(data) }
    {
    }
};

@KerrekSB,OP 问了关于团队混乱和浪费时间的问题吗? - Slava
2
@101010 那么两者都不会编译。这是一件好事。 - juanchopanza
1
@101010 “bar<int> b{ std::move(other) };” - 这里是谁在提问? - keith
1
@Slava:OP 问的是“有什么区别”。使用 C++ 的目的是为了完成任务,因此如果对完成任务的能力产生影响,我认为这是值得注意的。 - Kerrek SB
相关/可能重复:[1](https://dev59.com/81oU5IYBdhLWcg3wAjYs),[2](https://dev59.com/QVoT5IYBdhLWcg3w0SGZ) - NathanOliver
显示剩余8条评论
1个回答

7

绑定到引用需要少移动一个操作:

void f(std::unique_ptr<T>&& p) { g(std::move(p)); }

f(std::make_unique<T>());  // no move, g binds directly to the temporary

绑定到对象参数需要一个实际的移动:

void f(std::unique_ptr<T> p) { g(std::move(p)); }

f(std::make_unique<T>());  // p constructed (= moved) from temporary,
                           // g binds to p

额外的步骤包括一个指针复制,一个将指针设置为null,以及一个带有条件检查的析构函数。这不是很大的成本,使用哪种风格取决于你正在编写的代码类型:
如果你的代码更为简单且使用较少,则通过按值传递来实现简化的版本更加合适。相反,如果你的代码更多地涉及库和你不太了解用户,则在避免可避免的成本方面具有更高的价值,无论这些成本有多小。
你自己决定。

在C++17中,那个额外的移动操作将被保证被省略掉,对吧? - NathanOliver
2
@NathanOliver:不,那与此无关。这就是为什么我讨厌“保证复制省略”这个术语,它只会让每个人都感到困惑。 - Kerrek SB
@NathanOliver:基本上,你应该拒绝所有空洞的“X将解决所有Y”的说法,它们都是无意义的。 - Kerrek SB
那么你会给它什么术语呢? - Hatted Rooster
4
@GillBates:也许是“简化值类别”,类似这样的东西。“Prvalues不是对象”。后者准确地描述了更改。现在很清楚为什么这与当前问题无关。它也不会因为不存在的东西而做广告。 - Kerrek SB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接