如何返回一个智能指针指向类成员变量?

20

我正在尝试使用智能指针为一个类成员变量创建访问器。以下是代码:

class MyResource
{
};

class MyClass
{
public:
    std::unique_ptr<MyResource> getResource();
private:
    std::unique_ptr<MyResource> resource;
};

std::unique_ptr<MyResource> MyClass::getResource()
{
    return this->resource;
}

编译出现的错误:

无法访问声明在‘std::unique_ptr<_Ty>’类中的私有成员

this->resource添加.get当然行不通,因为返回类型会改变。

我是否不应该在这里使用unique_ptr?这只是一个语法问题吗?我完全走错了吗?

我的智能指针背景:几年来我一直在使用普通指针,部分原因是我找不到一个确定何时使用哪种类型的智能指针以及如何使用它们的解释。我已经厌倦了找借口,所以我要深入学习。我认为我理解了智能指针是什么以及为什么要使用它们,但是我对其细节知之甚少。目前我在关于 智能 指针 无尽的 问答讨论中完全迷失了。


5
你不应该在这里使用独占指针。将其按值返回或将其变为共享指针。 - dwcanillas
3
您可以通过引用或原始指针返回它。 - Angew is no longer proud of SO
2
@Angew 是的,完全正确。唯一指针的整个重点在于它们是唯一的,即一个对象只有一个指针。 - dwcanillas
2
@OP 你知道 std::unique_ptr<MyResource> MyClass::getResource() 会将所有权转移给调用者吗?这很可能不是你想要的,除非你正在设计一个工厂。 - πάντα ῥεῖ
注意:在没有std::move(std::forward)的情况下,您无法转移所有权,请参见Barry的答案。 - user2249683
2个回答

30
最重要的是要理解智能指针的关键在于它们的“指针”方面并不是其语义中的基本部分。智能指针存在的意义在于代表所有权。所有权定义为清理的责任。
独占式指针表示:“我是pointee的唯一所有者。当我超出范围时,我将销毁它。”
共享指针表示:“我是一组分享pointee负责任的朋友之一。最后一个超出范围的人将摧毁它。”
(在现代C ++程序中),原始指针或引用表示:“我不拥有pointee,我只是观察它。其他人有责任将其销毁。”
在您的情况下,使用unique_ptr作为成员类型意味着MyClass拥有MyResource对象。如果getter应该传递所有权(也就是说,如果MyClass正在将资源转让给调用getter的人),则返回unique_ptr是合适的(您需要return std::move(resource);来使所有权转移明确)。
如果getter 应该放弃所有权(我认为这是可能的情况),只需返回一个简单的旧指针(如果返回空指针是一个选项)或一个简单的旧引用(如果返回null不是一个选项)。

虽然其他答案获得了更多的投票,但是对我个人来说,这个答案因为解释的原因是最有帮助的。现在我认为(我真心希望)我终于理解了这个问题。 - Logical Fallacy
@David 这正是为什么 SO 同时拥有投票和接受概念的原因 :-) 很高兴能够帮助到您。 - Angew is no longer proud of SO
3
第三种情况,我们很快也会有std::experimental::observer_ptr - T.C.

22

根据你希望你的类遵守的语义,你有几个选项。

  1. 你想放弃对资源的所有权:

std::unique_ptr<MyResource> MyClass::releaseResource() {
    return std::move(this->resource);
}
  • 你希望保持独特的所有权,但允许别人使用它:

  • MyResource& MyClass::getResource() {
        assert(this->resource);
        return *(this->resource);
    }
    
  • 您希望共享所有权,因此如果MyClass超出范围,则资源不会被销毁:将所有内容都切换到std :: shared_ptr<MyResource>并仍然按值返回。


  • 你更快,加一分 :-) - Angew is no longer proud of SO

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