在std::shared_ptr中检查空值

55

我在想,在使用sp之前是否需要检查它是否为null

如果我说错了,请纠正我,但创建别名不会增加引用计数器,因此进入方法时我们正在使用一个共享指针,我们不知道嵌入指针是否已被重置.. 我正确地假设了吗?

Class::MyFunction(std::shared_ptr<foo> &sp)
{    
    ...  
    sp->do_something();  
    ...  
}

3
只有当他可以使用C++11时才行。并非每个人都是具备控制自己工具链的业余程序员。 - Lightness Races in Orbit
1
@LightnessRacesinOrbit:确实(我承认,对于一个对冲基金来说,这是一种爱好),但是发展必要的个人有效性技能以推动公司前进是很重要的。 - Bathsheba
@Bathsheba:我同意,至少要在你自己的时间里写! - Lightness Races in Orbit
4个回答

74

你需要考虑到std::shared_ptr本质上仍然是一个指针(封装在类似指针的类中),它确实可以被构造为内部为nullptr。当这种情况发生时,如下表达式:

ptr->
*ptr

导致未定义的行为。所以,是的,如果你期望指针也是nullptr,那么你应该使用以下方式检查其值

ptr != nullptr

或者

!ptr

感谢它的operator bool

9
除非你的目的是混淆视听,否则应避免使用!ptr。它存在的原因是为了模拟裸指针,但这是从C继承来的一个缺陷,在编写良好的代码中应该避免使用它(即使在C中也是如此)。 - James Kanze
3
@JamesKanze C和C++都部分地基于“0 == false”的假设,这种情况无处不在,你无法避免它,更不用说远离它。即使我很久没有接触C语言了,但这种关联已经深深地烙印在我的程序员大脑中,我认为许多其他的C++程序员也有同感。 - JMB
2
ptr和ptr->等同于get()和get()。这不是未定义的,你为什么说它是未定义的? - Epirocks
@Epirocks 我认为 OP 的意思是当受管指针为空时,它是未定义的行为。无论智能指针如何,解引用空指针都不是定义良好的行为。 - reirab
@JamesKanze 这不是混淆,而是C和C++中布尔上下文的基本行为。任何nullptr0的值在布尔上下文中都会被解释为false。这是完全正常的。否则,你需要在各个地方编写if (someValue == 0)if (somePointer == nullptr)。按照你的逻辑,你必须写if (someBoolean == false)而不是if (!someBoolean)对吗?但是等等,那么你就需要写if ((someBoolean == false) == true),否则我猜这就是“混淆”了吧? - ThreeStarProgrammer57

23

大多数共享指针在这方面与普通指针完全相同。您必须检查是否为null。根据函数,您可能希望切换到使用

void myFunction( Foo const& foo );

通过对指针进行取消引用操作来调用它(这将把确保指针不为null的责任推给调用者)。

此外,除非有特殊的所有权语义涉及,否则使函数接受一个shared_ptr可能是不好的实践。如果函数只是在函数执行期间使用指针,而不会更改它或拥有它,则原始指针可能更合适,因为它对调用者施加的约束较少。(但这实际上取决于函数的行为以及您为什么使用共享指针。当然,传递非const引用到共享指针的事实意味着您将要修改它,因此传递共享指针可能是合适的。)

最后,不同的共享指针实现使检查空值更或少困难。使用C++11,您可以使用std::shared_ptr自然地将其与nullptr进行比较,就像您期望的那样。然而,Boost实现在这方面有些问题;您不能将它与0NULL直接比较。您必须为比较构造一个空的boost::shared_ptr,或者调用get并将得到的原始指针与0NULL进行比较。


4

3
什么意思,没有意义?我们对这个功能所做的了解很少。而且你不需要使用 get() 来检查空值。 - Angew is no longer proud of SO
2
“将shared_ptr作为引用传递是没有意义的” - [需要引用]. 您可以通过const引用传递(即“明确模块API不影响值”),或者通过引用传递(即“将其视为输出变量”)。通过(const)引用传递可能会被编码约定、技术原因(“模板特化将参数作为const引用接收”)等强制执行。 - utnapistim
@utnapistim,这个问题之前已经被问过了:https://dev59.com/mWsy5IYBdhLWcg3wsADQ。 - Samuel
@Angew,使用boost::shared_ptr时,你需要使用get,或者你需要构造一个空的boost::shared_ptr进行比较,或者你需要使用混淆的隐式转换。使用get可能是最好的(或最不坏的)解决方案。 - James Kanze
引用线程中得票最高的答案完全是错误的。首先,这里(和那里)的问题涉及非const引用。如果这确实是所需的,这意味着被调用的函数可能会修改参数,这需要一个引用。否则,共享指针是用户定义的类型,因此通常规则是通过const引用而不是值传递它。 - James Kanze
显示剩余4条评论

2
这个问题没有通用答案,你需要像对待其他指针一样处理它。如果你不确定它是否为空,就进行测试。如果你相信它永远不会为空,assert() 它不为空并直接使用它。
拥有 shared_ptr 的引用或者 shared_ptr 本身对此没有影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接