C++ 转移唯一所有权:唯一性与移动语义

C++ 转移唯一所有权:唯一性与移动语义,c++,c++11,move-semantics,unique-ptr,C++,C++11,Move Semantics,Unique Ptr,似乎std::unique\u ptr解决了一个同样可以用移动语义解决的问题,即转移唯一拥有的资源的所有权。以下是一些他们似乎执行相同工作的示例: class SomeResource { /* resourcey stuff */ }; void ProcessResourcePtr(std::unique_ptr<SomeResource> r) { /* do stuff */ } void ProcessResourceRvalRef(SomeResource&&a

似乎
std::unique\u 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;
}
class SomeResource{/*resourcey stuff*/};
void ProcessResourcePtr(std::unique\u ptr){/*do stuff*/}
void ProcessResourceRvalRef(SomeResource&&r){/*do stuff*/}
类所有者资源所有者{
私人:
std::唯一的;
公众:
OwnerOfResourcePtr(std::unique_ptr r):r(std::move(r)){}
};
类所有者资源参考{
私人:
一些资源;
公众:
OwnerOfResourceRvalRef(SomeResource&&r):r(std::move(r)){}
};
int main()
{
//通过唯一ptr将所有权转移至职能部门
std::unique_ptr r1(new SomeResource());
ProcessResourcePtr(std::move(r1));
//通过右值ref将所有权转移到函数
一些资源r2;
ProcessResourceRvalRef(std::move(r2));
//通过唯一的ptr将所有权转移到实例
std::unique_ptr r3(new SomeResource());
所有者:资源中心(标准::移动(r3));
//通过右值ref将所有权转移到实例
一些资源r4;
所有者资源参考(标准::移动(r4));
返回0;
}
在我看来,这两种方法解决几乎完全相同的问题的方式略有不同。我不是100%清楚一种方法与另一种方法的优势。我知道指针移动可能比移动构造函数/赋值更快,尽管通常认为两者都非常有效。我还知道,移动语义允许您将数据保留在堆栈上(请参见r2、r4),而不需要使用new/malloc/etc(请参见r1、r3)进行堆分配/释放,我认为这是一件好事(是吗?)

一般来说,什么时候应该选择
唯一的\u ptr
而不是移动语义,或者反之亦然?是否存在只能由一个或另一个解决的用例?

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

如果实例是可选的,即可能不存在,则应使用
unique\u ptr

如果只能在调用构造函数后初始化对象,并且该对象不是默认可构造的,则必须延迟构造,并且可以为此使用
unique\u ptr


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

如果实例是可选的,则应使用
std::experional::optional
boost::optional
。为此使用
std::unique\u ptr
是没有意义的。而且,我认为OP的问题根本没有意义
std::unique_ptr
显示可重用的所有权策略包。它感觉到归结为“我应该何时使用<代码> STD::UNQuijyPTR <代码>代替我自己的所有权策略?”@ RAPTZ:<代码> STD::UnQuyGyPt/<代码>是标准C++的一部分,对于某些人来说,它比实验或 Boost 具有明显的优势。我同意OP似乎在寻找一个借口来避免
std::unique_ptr
,而实际上它非常有用。
std::experimental::optional
在技术上也是标准的一部分。就像TR1中的内容是当时标准的一部分一样。clang和gcc都支持std::experimental::optional;我意外地创建了我自己的所有权政策,但感觉好像有点不对劲,因为我没有使用<代码> UNQuyGyPTR <代码>(对于C++来说是很新的,如果不明显)。我知道
unique\u ptr
肯定有一些优势,否则他们不会费心去做,但由于我的政策没有造成任何问题,所以我没有看到他们@约翰·兹温克(John Zwinck)出色地描述了我的政策在未来会遇到哪些痛点@Rapptz,我将阅读各种
可选
软件包。知道你是否使用它们似乎很好。谢谢大家。@Rapptz:
std::experimental
不是任何标准的一部分
TR1
从来都不是任何标准的一部分。它们只是实验。您可以将其视为标准委员会的声明:我们对该API感兴趣,我们正在寻求更多的现场经验和反馈。事实上,这就是为什么我极力游说名称空间“实验性”而不是容易被误解的“tr1”。