47

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

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

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

我的问题是这个——

  • 然后我应该如何将device _ 变量传递给所有需要它作为参数的函数?

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

或者我可以更改每个函数,以便现在采用“std::unique_ptr&”类型的参数,而不是采用“Device*”类型的参数。这(对我来说)有点混淆了函数原型,使它们难以阅读。

对此的最佳做法是什么?我错过了其他选择吗?

4

5 回答 5

45

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

  • 所有权
  • 无效

所有权是关于某些对象/资源的所有者(在这种情况下,是 的一个实例Device)。各种std::unique_ptr, boost::scoped_ptrorstd::shared_ptr是关于所有权的。

然而,空值要简单得多:它只表示给定对象是否为空,不关心其他任何事情,当然也不关心所有权!


您将类的实现移向(通常)是正确unique_ptr的,但如果您的目标是实现 PIMPL,您可能需要一个具有深拷贝语义的智能指针。

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


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

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

因此,选择如何传递参数取决于它可能的Nullity

  • 从不为空?传递参考
  • 可能为空?传递一个指针、一个简单的裸指针或一个类似指针的类(例如在 null 上带有一个陷阱)

于 2012-03-14T10:31:55.840 回答
14

这真的取决于。如果一个函数必须拥有 unique_ptr 的所有权,那么它的签名应该采用unique_ptr<Device>bv,而调用者应该std::move采用指针。如果所有权不是问题,那么我将保留原始指针签名并使用get(). 如果所讨论的功能没有接管所有权,这并不难看。

于 2012-03-14T09:50:46.390 回答
8

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

于 2012-03-14T09:47:07.453 回答
2

在这种情况下,最好的做法可能是不要使用std::unique_ptr,尽管这取决于情况。(您通常不应该有多个指向类中动态分配的对象的原始指针。尽管这也取决于。)在这种情况下您不想做的一件事是传递std::unique_ptr(正如您已经注意到的那样, std::unique_ptr<> const&有点笨拙和令人困惑)。如果这是对象中唯一动态分配的指针,我会坚持使用原始指针和delete析构函数中的。如果有几个这样的指针,我会考虑将它们中的每一个降级为一个单独的基类(它们仍然可以是原始指针)。

于 2012-03-14T09:57:55.483 回答
1

这对您来说可能不可行,但是替换每一次出现的Device*byconst unique_ptr<Device>&是一个好的开始。

你显然不能复制unique_ptrs 并且你不想移动它。替换为引用unique_ptr允许现有函数的主体继续工作。

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

于 2012-03-14T09:49:52.833 回答