Несовместимость при разыменовании вернула пустую shared_ptr

Недавно я заметил странное поведение при использовании возвращенного пустого shared_ptr. Чтобы проиллюстрировать проблему, рассмотрим этот пример:

    struct A {
A() { }
void foo() {
std::cout << "A::foo" << std::endl;
}
};

struct B {
B() :i(42) { }
void foo() {
std::cout << "B:foo with i: " << i << std::endl;
}

int i;
};

template<typename T>
std::shared_ptr<T> create_empty() {
return std::shared_ptr<T>();
}

Тогда звоню:

    std::shared_ptr<A> pa(create_empty<A>());
pa->foo(); // #1: Works fine and prints: "A::foo".

std::shared_ptr<B> pb(create_empty<B>());
pb->foo(); // #2: Throws an exception.

Теперь мой вопрос: почему вызов # 1 работает (я ожидал также получить исключение) и если это правильное поведение, как запретить работу # 1. Я должен проверить, является ли возвращаемое значение пустым? Есть ли другие способы вернуть null или пустой shared_ptr? Я использую MSVC ++ 11, если это имеет значение …

3

Решение

Код в обоих случаях разыменовывает нулевой указатель. Поведение не определено, поэтому может случиться что угодно, включая вещи, которые, кажется, имеют смысл. Не пытайтесь осмыслить их. Не определено не определено.

3

Другие решения

Ни один из примеров действительно не работает, так как они используют нулевой указатель.

В первом случае вы действительно ничего не получаете от A, поэтому можете не заметить. Во втором случае доступ к i члену крайне вероятно придется разыменовать this указатель (и система заметит, что он нулевой).

1