16
votes

My question concerns shared_ptr and make_shared in C++11. I have two vectors, the first one stores smart pointers and the second one stores raw pointers. The first vector works as I had expepted but vector2 is just confusing...

Code sample

#include <iostream>
#include <vector>
#include <memory>

int main() {
    std::vector<std::shared_ptr<int>> vector1;
    vector1.push_back(std::make_shared<int>(1));
    vector1.push_back(std::make_shared<int>(2));
    vector1.push_back(std::make_shared<int>(3));

    std::vector<int*> vector2;
    vector2.push_back(std::make_shared<int>(4).get());
    vector2.push_back(std::make_shared<int>(5).get());
    vector2.push_back(std::make_shared<int>(6).get());

    std::cout << "vector1 values:" << std::endl;
    for(auto &value: vector1) { std::cout << *value << std::endl; }

    std::cout << "vector2 values:" << std::endl;
    for(auto &value: vector2) { std::cout << *value << std::endl; }

    return 0;
}


Output

vector1 values:
1
2
3
vector2 values:
6
6
6


Question

I realize that it would be much simpler to create raw pointers to begin with and not try to convert smart pointers but it made me curious to know why this is happening? Also why does each push change all of the values in vector2?


Links

Here are some questions that I found in stackoverflow but they didn't answer my question or maybe I didn't understand the answers...

2
Great first question! Very well formatted.yizzlez

2 Answers

10
votes

You are seeing undefined behaviour. When you do this:

vector2.push_back(std::make_shared<int>(4).get());

You are creating a temporary shared_ptr, and copying a pointer to its managed object into your vector. This immediately becomes a dangling pointer.

10
votes

The reason you'll use a shared_ptr is that you want the memory it points to to be freed when all instances that point to it go out of scope. The shared_ptr is destroyed right after you call .get() on it, so you immediately have a dangling pointer. The result of the dereference operation is undefined, which means that it may or may not return a value that makes sense, or it could even do something completely unrelated (like crashing).

This is a feature. You want this to happen: otherwise, you'd be leaking memory. Imagine this code:

vector<int> integers;
integers.push_back(*make_shared<int>(6).get());

If the memory wasn't freed, there would be no way to release it afterwards, because there's no way you could recover the shared_ptr's managed pointer.