我正在尝试“现代化”一些现有代码。

  • 我有一个类,当前有一个成员变量“Device* device_”。
  • 它在一些初始化代码中使用new创建实例,并在析构函数中具有“delete device_”。
  • 调用该类的成员函数 许多 其他以 Device* 作为参数的函数。

这很好用,但是为了“现代化”我的代码,我认为我应该将变量定义为 "std::unique_ptr<Device> device_" 并删除对删除的显式调用,这使得代码更安全并且总体上更好。

我的问题是这样的——

  • 那么我应该如何通过 设备_ 变量到所有需要它作为参数的函数?

我可以调用 .get 来获取每个函数调用中的原始指针。但这看起来很难看,并且浪费了一些首先使用 unique_ptr 的理由。

或者我可以改变 每一个 函数现在不再采用“Device*”类型的参数,而是采用“std::unique_ptr&”类型的参数。(对我来说)这在某种程度上混淆了函数原型,并使它们难以阅读。

对此的最佳实践是什么?我是否错过了其他选择?

有帮助吗?

解决方案

现代的 C++风格,有两个关键概念:

  • 所有权
  • 无效性

所有权 是关于某个对象/资源的所有者(在本例中是 Device)。各种种类 std::unique_ptr, boost::scoped_ptr 或者 std::shared_ptr 是关于所有权的。

无效性 然而要简单得多:它只是表达给定的对象是否可能为空,并且不关心其他任何事情,当然也不关心所有权!


你之前是 正确的 推动你的班级的实施 unique_ptr (一般来说),但如果您的目标是实现 PIMPL,您可能需要具有深层复制语义的智能指针。

这清楚地表明您的类是这块内存的唯一负责人,并且巧妙地处理了内存可能泄漏的所有各种方式。


另一方面,大多数 用户 资源的所有权并不关心它的所有权。

只要函数不保留对对象的引用(将其存储在映射或其他东西中),那么重要的是对象的生命周期超过函数调用的持续时间。

因此,选择如何传递参数取决于其可能的情况 无效性:

  • 永远不为空?通过一个 参考
  • 可能为空?通过一个 指针, ,一个简单的裸指针或类似指针的类(例如,带有 null 陷阱)

其他提示

这确实取决于。如果一个函数必须拥有 unique_ptr 的所有权,那么它的签名应该采用 unique_ptr<Device> 乙肝病毒 价值 并且调用者应该 std::move 指针。如果所有权不是问题,那么我将保留原始指针签名并使用传递指针 unique_ptr get(). 。这并不难看 如果 相关函数不会接管所有权。

我会用 std::unique_ptr const&. 。使用非常量引用将使被调用函数可以重置指针。
我认为这是一个很好的方式来表达您被调用的函数可以使用指针,但不能使用其他任何东西。
所以对我来说这将使界面更容易阅读。我知道我不必摆弄传递给我的指针。

最佳实践可能是不使用 std::unique_ptr 在这种情况下,尽管取决于。(通常,您不应有一个以上的原始指针,指向类动态分配的对象。虽然这也取决于。)在这种情况下,您不想做的一件事是通过 std::unique_ptr (正如你所注意到的,std::unique_ptr<> const& 有点笨拙和混乱)。如果这是对象中唯一动态分配的指针,我只是坚持使用原始指针, delete 在析构函数中。如果有几个这样的指针,我会考虑将它们降级到单独的基类(它们仍然可以是原始指针)。

这对你来说可能不可行,但可以替换每次出现的情况 Device* 经过 const unique_ptr<Device>& 是一个好的开始。

显然你无法复制 unique_ptrs 并且您不想移动它。替换为引用 unique_ptr 允许现有职能机构继续工作。

现在有一个陷阱,你必须通过 const & 防止被调用者做 unique_ptr.reset() 或者 unique_ptr().release(). 。请注意,这仍然将可修改的指针传递给设备。使用此解决方案,您没有简单的方法来传递指针或引用 const Device.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top