【问题标题】:Dereference a shared_ptr returned from a function取消引用从函数返回的 shared_ptr
【发布时间】:2013-11-05 17:13:21
【问题描述】:

我有一个类DevicePointer,它封装了std::shared_ptr<Device>。需要保存指向设备的指针的各种类派生自DevicePointer。在我开始使用shared_ptr 之前,DevicePointer 有一个::Expose() 函数,它将返回一个指向设备的原始指针。现在我使用 shared_ptr 来保存设备指针,我不知道如何返回它。请注意,应该调用 ::Expose 的唯一原因是取消对指针的引用。

这是原来的 Expose 的样子:

Device * Expose() const  { return MyDevice; }

并且会像这样使用:

Device::Expose()->ExecuteFunction(a, b, c);

现在MyDevicestd::shared_ptr<Device>,我不知道如何返回它以解除引用。显而易见的选择是:

std::shared_ptr<Device> Expose() {
    return MyDevice;
}

但我担心性能,尤其是创建一个新的临时std::shared_ptr。所以我需要某种方式说“你可以取消引用这个指针,但你不能复制它”。原始文件仍然需要共享,因为许多对象都会持有对它的引用。

我希望我已经充分表达了我的问题。谢谢。

【问题讨论】:

  • 请澄清您的问题。您的函数Device &amp; Expose() 没有返回原始指针,而是返回引用。如果您想从共享指针访问底层指针,您可以使用get 方法(参见en.cppreference.com/w/cpp/memory/shared_ptr)。
  • 好的,已编辑以减少歧义。现在只返回一个指针。
  • 我更新了答案以解释如何防止 MyDevice 没有副本。
  • 请问为什么需要暴露底层指针?也就是说,为什么需要这样做:Device::Expose()-&gt;ExecuteFunction(a, b, c),而不是简单地这样做:Device-&gt;ExecuteFunction(a, b, c)?请注意,std::shared_ptr 将正确处理 -&gt; 运算符。

标签: c++ shared-ptr


【解决方案1】:

这不会影响性能

Device & Expose() {
    return *MyDevice.get();
}

编辑:

使对象不可复制:

class Device
{

private:
    //compiler will throw errors when copy constructor or = is called in the code
    Device(const Device &)
    {}
    void operator = (const Device &)
    {
    }
};

编辑(2018-09-05):

从 c++11 开始,您可以显式删除复制构造函数或赋值运算符:

class Device
{
public:
    Device(const Device &) = delete;
    Device& operator = (const Device &) = delete;
};

【讨论】:

  • 这里不用打.get()
  • 我想就是这样(减去 .get())。除了彼得所说的无法阻止来电者获取副本。嗯。
  • 是的,你是对的,不需要调用get,我通常避免不调用它,以便其他程序员知道MyDevice是一个共享/侵入性ptr。
【解决方案2】:

(编辑:这里的第一段是指您的原始问题,您在函数中取消引用指针并返回引用。)

像这样取消引用指针似乎不太安全,因为它让调用者有责任在无法看到指针的情况下确定操作的安全性。如果指针为空,就会出错。

因此,我建议只返回shared_ptr 的副本。除非您每秒调用数百次,否则性能影响应该不会很大。

很遗憾,没有办法防止复制。无论您返回指针还是引用,调用者都可以轻松获取副本。

【讨论】:

  • 是的,很抱歉。我对其进行了编辑,因为我通过谈论指针但将其作为参考返回来混淆了这个问题。所以我把它改成了一个指向对象的指针。
【解决方案3】:

如果您的应用程序是多线程的,并且您的对象可以随时以异步方式“销毁”,那么除了返回 shared_ptr 副本之外别无选择。 如果您确定对象的生命周期,则可以返回对 shared_ptr 的引用。但这可能会在您的代码升级后成为麻烦。取消引用指针 (shared_ptr::get) 也是如此,因为当代码变得更加复杂并且对象的生命周期变得难以跟踪时,将来支持该代码将非常困难。

【讨论】:

    猜你喜欢
    • 2017-06-18
    • 2012-09-05
    • 1970-01-01
    • 2017-05-02
    • 2014-01-23
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    相关资源
    最近更新 更多