1

我可以访问 null shared_ptr 对象的成员函数:

#include <memory>
#include <iostream>

class A
{
public:
    int getNum() {return 1234;}
};

int main()
{
    std::shared_ptr<A> pA(nullptr);
    std::cout << pA->getNum() << std::endl;
}

在我期待异常时返回 1234。同样的结果发生在

std::shared_ptr<A> pA();

或者

std::shared_ptr<A> pA();
pA.reset();

这真的是预期的行为吗?如果是在成员函数调用的情况下引发异常的 corect shared_ptr 定义是什么?

使用VS2010。

4

3 回答 3

9

调用operator->()ashared_ptr需要 [util.smartptr.shared.obs]:

5要求get() != 0

这意味着如果get() == 0你调用operator->(),你会得到未定义的行为。未定义的行为意味着任何事情都可能发生:您可能会遇到异常。您可以获得预期的结果(无论是什么)。您可以备份最近的主要城市的所有厕所。只是没有说法。

无论您的实现如何处理此代码,实现都是正确的。

于 2011-04-05T01:40:21.177 回答
7

完整的答案在这里:

何时在空实例上调用成员函数会导致未定义的行为?

简短的回答是,是的,这是未定义的行为(或者,至少,在规范中没有明确定义),并且实际行为并非不合理,因为它静态地知道类型并且不引用任何数据在其中。然而,指望这种行为几乎肯定不是一个好主意。

于 2011-04-05T01:40:45.780 回答
6

从技术上讲,您在这里所做的确实需要未定义的行为。但是,由于您的getNum方法不是virtual并且根本没有使用this,所以这次它恰好不会崩溃。要了解原因,假设编译器在内部重写了您的程序,如下所示:

class A { };

int A_getNum(A* this) { return 1234; }

int main()
{
  A* pA = 0;
  std::cout << A_getNum(pA) << '\n';
}

您可以看到即使没有实际对象,空指针也不会被取消引用A,因此它不会崩溃。shared_ptr无关紧要——如果您使用裸指针,您将获得相同的效果。

如果您想在空指针上使用时强制 shared_ptr使您崩溃->,嗯,我不相信有任何标准。你的编译器可能有一个你可以打开的调试选项——例如,如果我用 gcc 4.5 编译你的程序-D_GLIBCXX_DEBUG,我得到

$ ./a.out 
/usr/include/c++/4.5/bits/shared_ptr_base.h:710: 
_Tp* std::__shared_ptr<_Tp, _Lp>::operator->() const 
[with _Tp = A, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]: 
Assertion '_M_ptr != 0' failed.
Aborted

无法帮助您使用 MSVC,抱歉。

于 2011-04-05T01:46:31.593 回答