lve*_*lla 72 c++ unique-ptr c++11
我第一次尝试使用C++ 11 unique_ptr; 我正在替换我的一个项目中的多态原始指针,该指针由一个类拥有,但经常传递.
我以前的功能如下:
bool func(BaseClass* ptr, int other_arg) {
bool val;
// plain ordinary function that does something...
return val;
}
Run Code Online (Sandbox Code Playgroud)
但我很快意识到我无法切换到:
bool func(std::unique_ptr<BaseClass> ptr, int other_arg);
Run Code Online (Sandbox Code Playgroud)
因为调用者必须处理函数的指针所有权,所以我不想这样做.那么,什么是我的问题的最佳解决方案?
我虽然将指针作为参考传递,如下所示:
bool func(const std::unique_ptr<BaseClass>& ptr, int other_arg);
Run Code Online (Sandbox Code Playgroud)
但是我觉得这样做非常不舒服,首先是因为传递已经输入的内容似乎并非本能,_ptr作为参考的参考.其次,因为功能签名变得更大.第三,因为在生成的代码中,需要两个连续的指针间接来达到我的变量.
R. *_*des 86
如果希望函数使用指针对象,请传递对它的引用.没有理由将该函数与仅使用某种智能指针相关联:
bool func(BaseClass& base, int other_arg);
Run Code Online (Sandbox Code Playgroud)
并在通话现场使用operator*:
func(*some_unique_ptr, 42);
Run Code Online (Sandbox Code Playgroud)
或者,如果base允许参数为null,则保持签名不变,并使用get()成员函数:
bool func(BaseClass* base, int other_arg);
func(some_unique_ptr.get(), 42);
Run Code Online (Sandbox Code Playgroud)
Vic*_*avu 27
使用std::unique_ptr<T>(除了不必记住调用delete或delete[]显式)之外的优点是它保证指针是或者nullptr指向(基础)对象的有效实例.在我回答你的问题后,我会回到这个问题,但第一个信息是DO使用智能指针来管理动态分配对象的生命周期.
现在,您的问题实际上是如何在旧代码中使用它.
我的建议是,如果您不想转移或共享所有权,则应始终传递对该对象的引用.像这样声明你的函数(const根据需要使用或不使用限定符):
bool func(BaseClass& ref, int other_arg) { ... }
Run Code Online (Sandbox Code Playgroud)
然后调用者有一个std::shared_ptr<BaseClass> ptr将处理nullptr案件或将要求bool func(...)计算结果:
if (ptr) {
result = func(*ptr, some_int);
} else {
/* the object was, for some reason, either not created or destroyed */
}
Run Code Online (Sandbox Code Playgroud)
这意味着任何调用者都必须承诺引用是有效的,并且它将在函数体的执行过程中继续有效.
这是为什么我坚信你应该之所以没有通过原始指针或引用智能指针.
原始指针只是一个内存地址.可以有(至少)4个含义之一:
正确使用智能指针缓解了相当可怕的情况下,3和4,它们通常不会在编译时和你一般只检测经验在运行时,当你的程序崩溃或做意想不到的事情.
将智能指针作为参数传递有两个缺点:您无法在不进行复制的情况下更改指向对象的const-ness (这会增加开销并且不可能),并且您仍然保留第二个()含义.shared_ptrunique_ptrnullptr
我从设计角度将第二种情况标记为(坏).这是一个关于责任的更微妙的论点.
想象一下当函数接收a nullptr作为其参数时它意味着什么.它首先必须决定如何处理它:使用"神奇"值代替丢失的对象?完全改变行为并计算其他东西(不需要对象)?恐慌并抛出异常?此外,当函数通过原始指针获取2个,3个甚至更多个参数时会发生什么?它必须检查每一个并相应地调整其行为.除了真正的原因之外,这在输入验证之上增加了一个全新的水平.
呼叫者应该是具有足够上下文信息的人来做出这些决定,或者换句话说,坏事不会越少,你知道的越多.另一方面,该函数应该只是接受调用者的承诺,即它所指向的内存可以安全地按预期使用.(引用仍然是内存地址,但在概念上代表了有效性的承诺.)
Mik*_*son 22
我同意Martinho,但我认为指出pass-by-reference的所有权语义非常重要.我认为正确的解决方案是在这里使用简单的pass-by-reference:
bool func(BaseClass& base, int other_arg);
Run Code Online (Sandbox Code Playgroud)
C++中传递引用的普遍接受的含义就像函数的调用者告诉函数"在这里,你可以借用这个对象,使用它,并修改它(如果不是const),但仅限于功能体的持续时间." 这绝不会与所有权规则相冲突,unique_ptr因为对象只是在短时间内被借用,没有实际的所有权转移(如果你把车借给某人,你是否签了标题)对他来说?).
因此,即使将引用(甚至是原始指针)拉出来也可能看起来很糟糕(设计方面,编码实践等)unique_ptr,但实际上并不是因为它完全符合所设置的所有权规则.这个unique_ptr.然后,当然,还有其他一些很好的优点,例如干净的语法,对a所拥有的对象没有限制unique_ptr,等等.