Reputation: 872
Consider the following snippet:
#include <memory>
#include <typeinfo>
#include <iostream>
class Widget {
};
int main() {
auto shared_ptr_to_widget = std::shared_ptr<Widget>({});
std::cout << "type of shared_ptr_to_widget: " << typeid(shared_ptr_to_widget).name() << std::endl;
auto maybe_a_widget = *shared_ptr_to_widget;
std::cout << "type of maybe_a_widget: " << typeid(maybe_a_widget).name() << std::endl;
}
This will output:
> type of shared_ptr_to_widget: St10shared_ptrI6WidgetE
> type of maybe_a_widget: 6Widget
However, if I replace the Widget class with:
class Widget {
public:
Widget(): a{1}{}
int a;
};
Then it seg faults at the following line:
auto maybe_a_widget = *shared_ptr_to_widget;
I understand if I actually wanted to make a shared pointer to an instance of an object I should use
std::make_shared<Widget>()
and this would actually call the constructor of Widget and everything would be fine and dandy. But I'd really like to understand what is going on here and why the behaviour changes based on the constructor of the Widget class.
I've tried looking at the constructors for shared_ptr http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr but I get a bit lost. I imagine it's my lack of understanding in what is actually happening when using an empty initializer list as a parameter to shared_ptr<>().
Upvotes: 0
Views: 98
Reputation: 477000
Your code has undefined behaviour, since *shared_ptr_to_widget
dereferences a null pointer, since you only default-constructed shared_ptr_to_widget
, which results in an empty shared pointer that doesn't own anything.
At the point where the program execution has undefined behaviour, the C++ standard imposes no constraints on the behaviour of a conforming implementation, so anything can happen. You are observing a particular instance of "anything".
To create a pointer that owns a widget, say either
auto shared_ptr_to_widget = std::shared_ptr<Widget>(new Widget); // bad
or
auto shared_ptr_to_widget = std::make_shared<Widget>(); // good
Upvotes: 2