C++ 将唯一的\u ptr传递给函数

C++ 将唯一的\u ptr传递给函数,c++,smart-pointers,unique-ptr,C++,Smart Pointers,Unique Ptr,我正在尝试“现代化”一些现有的代码 我有一个类,它当前有一个成员变量“Device*Device\ux” 它使用new在一些初始化代码中创建一个实例,并且在析构函数中有一个“delete device” 此类的成员函数调用许多以设备*为参数的其他函数 这很好,但是为了使我的代码“现代化”,我认为应该将变量改为定义为“std::unique\u ptr device”,并删除对delete的显式调用,这使代码更安全,总体上更好 我的问题是- 然后如何将设备变量传递给所有需要它作为参数的函数

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

  • 我有一个类,它当前有一个成员变量“Device*Device\ux”
  • 它使用new在一些初始化代码中创建一个实例,并且在析构函数中有一个“delete device”
  • 此类的成员函数调用许多以设备*为参数的其他函数
这很好,但是为了使我的代码“现代化”,我认为应该将变量改为定义为
“std::unique\u ptr device”
,并删除对delete的显式调用,这使代码更安全,总体上更好

我的问题是-

  • 然后如何将设备变量传递给所有需要它作为参数的函数
我可以调用。获取每个函数调用中的原始指针。但这看起来很难看,而且浪费了一些在第一时间使用独特的ptr的理由

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


这方面的最佳实践是什么?我是否错过了其他选项?

我会使用
std::unique\u ptr const&
。使用非常量引用将使被调用函数能够重置指针。
我认为这是一种很好的方式来表示被调用函数可以使用指针,但不能使用其他任何东西。

所以对我来说,这将使界面更容易阅读。我知道我不必摆弄传递给我的指针。

这对你来说可能不可行,但用
const unique\u ptr&
替换
设备*
的每次出现是一个好的开始

显然,您无法复制
unique\u ptr
s,也不想移动它。通过引用
unique\u ptr
进行替换,允许现有职能机构的主体继续工作


现在有一个陷阱,您必须通过
const&
来阻止被调用方执行
unique\u ptr.reset()
unique\u ptr().release()
。请注意,这仍然会向设备传递一个可修改的指针。使用此解决方案,您无法轻松地将指针或引用传递到
常量设备

,这取决于具体情况。如果函数必须拥有unique_ptr的所有权,那么它的签名应该采用
unique_ptr
bv,调用方应该
std::move
指针。如果所有权不是问题,那么我将保留原始指针签名,并使用
get()
传递唯一的指针。如果所讨论的功能没有接管所有权,这并不难看

最佳做法可能是在这种情况下不使用
std::unique\u ptr
, 尽管要看情况而定。(一般情况下,您不应该有一个以上的原料药。) 指向类中动态分配的对象的指针 在这种情况下,你不想做的一件事是 传递
std::unique\u ptr
(正如您所注意到的,
std::unique_ptr const&
有点笨重和混乱)。如果这 是对象中唯一动态分配的指针,我坚持 使用原始指针和析构函数中的
delete
。如果有 一些这样的指针,我会考虑把它们都降级为A。 单独的基类(它们仍然可以是原始指针)
  • 所有权
  • 无效
所有权是关于某个对象/资源的所有者(在本例中是
设备的一个实例)。各种
std::unique_ptr
boost::scoped_ptr
std::shared_ptr
都与所有权有关

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


您将类的实现移向
unique\u ptr
(通常)是正确的,但如果您的目标是实现PIMPL,则可能需要具有深度复制语义的智能指针

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


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

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

因此,选择如何传递参数取决于其可能的空值:

  • 永不失效?传递推荐信
  • 可能是空的?传递一个指针、一个简单的裸指针或类似指针的类(例如null上有一个陷阱)


为什么这一更改会使代码更安全、总体上更好?根据你的描述,我想说的恰恰相反。@James Kanze我同意,在这种情况下,unique_ptr似乎买不到任何东西。你可能是对的。我喜欢unique_ptr的“安全性”,因为您不必记住删除它,但在这种情况下似乎确实要付出一些代价。
unique_ptr
的真正安全性在于,您不需要在指针周围加上try块,以确保在出现异常时删除它。这意味着它不会在具有析构函数的对象中为您带来太多好处,除非您在构造函数中有特定的约束。(无论你是将delete放入析构函数,还是使用
unique_ptr
,从你必须记住的事情来看,结果都差不多。)@James Kanze是的,这是有道理的。有趣的是,要说清楚,在那里添加const意味着我不能以任何方式更改unique_ptr,但我可以通过unique_ptr调用包含对象的非const函数?@JohnB:Yes th