【问题标题】:Transferring sole ownership: unique_ptr vs move semantics转让唯一所有权:unique_ptr 与移动语义
【发布时间】:2014-12-18 15:27:29
【问题描述】:

似乎std::unique_ptr 解决了一个也可以通过移动语义解决的问题,即转移唯一拥有资源的所有权。以下是他们似乎执行相同工作的一些示例:

class SomeResource { /* resourcey stuff */ };

void ProcessResourcePtr(std::unique_ptr<SomeResource> r) { /* do stuff */ }
void ProcessResourceRvalRef(SomeResource&& r) { /* do stuff */ }

class OwnerOfResourcePtr {
private:
    std::unique_ptr<SomeResource> r_;
public:
    OwnerOfResourcePtr(std::unique_ptr<SomeResource> r) : r_(std::move(r)) { }
};

class OwnerOfResourceRvalRef {
private:
    SomeResource r_;
public:
    OwnerOfResourceRvalRef(SomeResource&& r) : r_(std::move(r)) { }
};


int main()
{
    // transfer ownership to function via unique_ptr
    std::unique_ptr<SomeResource> r1(new SomeResource());
    ProcessResourcePtr(std::move(r1));

    // transfer ownership to function via rvalue ref
    SomeResource r2;
    ProcessResourceRvalRef(std::move(r2));

    // transfer ownership to instance via unique_ptr
    std::unique_ptr<SomeResource> r3(new SomeResource());
    OwnerOfResourcePtr(std::move(r3));

    // transfer ownership to instance via rvalue ref
    SomeResource r4;
    OwnerOfResourceRvalRef(std::move(r4));

    return 0;
}

在我看来,它们都以略微不同的方式解决了几乎完全相同的问题。我不是 100% 清楚一种方式与另一种方式的优势。我知道指针移动可能比移动构造函数/赋值更快,尽管通常认为两者都非常有效。我也知道移动语义允许您将数据保留在堆栈上(请参阅 r2、r4),而不是需要使用 new/malloc/etc 进行堆分配/释放(请参阅 r1、r3),我认为这是一个很好的选择东西(是吗?)。

一般来说,什么时候应该更喜欢 unique_ptr 而不是移动语义,反之亦然?是否有任何用例只能通过一个或另一个来解决?

【问题讨论】:

    标签: c++ c++11 move-semantics unique-ptr


    【解决方案1】:

    如果您有一个没有移动构造函数(甚至可能没有复制构造函数)的类(可能由其他人编写),那么您可能必须使用unique_ptr

    如果实例是可选的,即可能不存在,您应该使用unique_ptr

    如果你只能在你的构造函数被调用之后初始化一个对象,并且该对象不是默认可构造的,你必须延迟构造,并且可以使用unique_ptr

    即使一个类有一个移动构造函数,这也可能比移动单个指针更昂贵。例如,如果该类包含几十个 POD 实例,或者一个数组。

    【讨论】:

    • 如果实例是可选的,您应该使用std::experimental::optionalboost::optional。为此使用std::unique_ptr 是没有意义的。另外,我认为OP的问题甚至没有意义。 std::unique_ptr 显示您可以重复使用的所有权策略包。感觉可以归结为“我什么时候应该使用std::unique_ptr 而不是我自己的所有权政策?”。
    • @Rapptz: std::unique_ptr 是标准 C++ 的一部分,对于某些人来说,这比 experimentalboost 具有明显的优势。我同意 OP 似乎在寻找避免 std::unique_ptr 的借口,而实际上它非常有用。
    • std::experimental::optional 在技术上也是标准的一部分。就像 TR1 中的东西在当时是标准的一部分一样。 clang 和 gcc 都支持std::experimental::optional
    • 你说的都对;我不小心创建了自己的所有权政策,但感觉有些不对劲,因为我没有使用unique_ptr(如果不是很明显,对 c++ 来说是很新的东西)。我知道unique_ptr 必须有一些优势,否则他们不会费心去做,但由于我的政策没有造成任何问题,我还没有看到他们。 @John Zwinck 出色地描述了我的政策在未来会遇到的痛点。 @Rapptz,我会阅读各种 optional 软件包。似乎很高兴知道您是否使用它们。谢谢大家。
    • @Rapptz: std::experimental 不是任何标准的一部分。 TR1 从来都不是任何标准的一部分。它们只是实验。您可以将它们视为标准委员会的说法:我们对这个 API 很感兴趣,我们正在寻求更多的现场经验和反馈。确实,这就是为什么我大力游说命名空间“experimental”而不是容易被误解的“tr1”。
    猜你喜欢
    • 2014-07-30
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 1970-01-01
    • 2015-05-16
    • 2013-04-07
    • 2014-12-06
    • 2022-01-24
    相关资源
    最近更新 更多