在公共成员函数中返回私有的unique_ptr

5

考虑以下类原型:

class ObjHandler {

    std::unique_ptr<Obj> GetPtr() { return obj; }

  private:
    std::unique_ptr<Obj> obj;
};

这会生成一个编译时错误,提示std::unique_ptr的复制构造函数已被删除。为什么这里没有应用移动语义?这是否与GetPtr()不拥有obj指针有关?我该如何实现我的代码(我需要一个成员函数,以最小开销返回拥有流的指针)?


返回一个拥有指针:这是否意味着原始所有者失去了所有权? - xtofl
是的,举个例子,如果“用户”不想让“obj”在“ObjHandler”实例超出范围时被销毁。 - Luigi Pertoldi
2个回答

10

unique实际上意味着“独占所有权”。创建所有权的副本毫无意义,因为那样它就不再是唯一的了。

你可能想要返回所包含对象的引用或者一个非拥有指针:

class ObjHandler {
   Object &get(){ return *obj; }
   Object *GetPtr() { return obj.get(); }
private:
   unique_ptr<Object> obj;
};

这篇文章是有关使用智能指针的何时/何地/为什么的非常好的讲解。

CppCoreGuidelines也提到了这一点:原始指针在定义上表明对象不是所有者。


一个原始指针的定义表明该对象不被拥有,这可能是正确的,也可能不正确,特别是当你在处理遗留的C++代码或与C代码进行接口时。在这种情况下,你经常会遇到拥有原始指针,它们被返回给你,并期望你自己进行内存释放。Windows API就是一个例子。 - zett42

7

为什么这里没有使用移动语义?

因为obj不是一个局部变量,所以语言不允许隐式移动它。

您可以使用std::move来移动它:

std::unique_ptr<Obj> GetPtr() { return std::move(obj); }

尽管这是您真正想要的,但我建议给函数命名为一些明确表明所有权已经转移(即this->obj变为null)的名称,例如MovePtrGetPtr的名称听起来像它不修改this->obj,只返回一个非所有指向受管理的对象的指针,即其行为如下:
Obj* GetPtr() const { return obj.get(); }

3
虽然这是原帖的要求,但也许并不是他真正想要的。你可能需要添加几行关于下一次调用GetPtr()时会发生什么的内容。 - Bo Persson
6
如果函数是按照这种方式实现的,重命名为"ConsumePtr()"可能是个好主意,以便让读者清楚地知道该操作会修改"ObjHandler"的状态。 - Christian Hackl
@BoPersson 感谢您的反馈。已经改进了回答。 - emlai

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