null shared_ptr может получить доступ к функциям-членам - PullRequest
1 голос
/ 05 апреля 2011

Я могу получить доступ к функциям-членам нулевого объекта 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.

Ответы [ 3 ]

9 голосов
/ 05 апреля 2011

Для вызова operator->() на shared_ptr требуется [util.smartptr.shared.obs]:

5 Требуется : get() != 0.

Это означает, что если get() == 0 при вызове operator->(), вы получите неопределенное поведение. Неопределенное поведение означает, что может произойти все что угодно: вы можете получить исключение. Вы можете получить ожидаемый результат (что бы это ни было). Вы можете сделать резервную копию всех туалетов в ближайшем крупном городе. Там просто ничего не сказано.

Независимо от того, что ваша реализация делает с этим кодом, реализация верна.

7 голосов
/ 05 апреля 2011

Полный ответ здесь:

Когда вызов функции-члена для нулевого экземпляра приводит к неопределенному поведению?

Короткий ответ: да,это неопределенное поведение (или, по крайней мере, не однозначно определенное в спецификации), и что фактическое поведение не является необоснованным, учитывая, что оно статически знает тип и не ссылается на какие-либо данные в нем.Однако рассчитывать на такое поведение почти наверняка не очень хорошая идея.

6 голосов
/ 05 апреля 2011

Технически, то, что вы здесь сделали, делает влечет за собой неопределенное поведение. Однако, поскольку ваш getNum метод не является virtual и не использует вообще ничего, что this, на этот раз не произойдет сбой. Чтобы понять почему, представьте, что компилятор внутренне переписал вашу программу следующим образом:

class A { };

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

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

Вы можете видеть, что нулевой указатель никогда не разыскивается 1010 *, даже если нет действительного объекта 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, извините.

...