Search code examples
c++pointerssmart-pointers

Does wrapping a pointer in shared_ptr guarantee it will be deleted if I continue to use the raw pointer?


I have a hash table generated at runtime, populated by global variables.

inline A* global1 = new A();
inline A* global2 = new A();
inline A* global3 = new A();

std::map<A*, int> createMap() {
     return std::map<A*, int>({{global1, 1}, {global2, 2}, {global3, 3}});
}

I want to add new entries to map during runtime, meaning that I'll have to create new pointers to A.

void doStuff(std::map<A*, int>& map) {
    A* runTimeValue = new A();
    map[runTimeValue] = 4;
}

However this opens up the program to memory leaks as I'll have to worry about deleting runTimeValue when the map object finally goes out of scope and is deleted. I considered switching the map to std::map<std::shared_ptr<A>, int> but working with std::shared_ptr<A> is difficult as it has many different subclasses.

One solution I had was to wrap runTimeValue in a shared_ptr so that it can automatically be deleted, and then continue using the raw pointer.

void doStuff(std::map<A*, int>& map) {
    A* runTimeValue = new A();
    std::shared_ptr<A> temp(runTimeValue);
    map[runTimeValue] = 4;
}

Would this work? Do I need to store a reference to temp till the map goes out of scope? Is there a better way of dealing with a mix of global and run time pointers where run time ones have to be deleted but globals do not?

Edit, example of "program" in use:

inline A* global1 = new A();
inline A* global2 = new A();
inline A* global3 = new A();

int main() {
    while(true) {
        std::map<A*, int> map = createMap();
        doStuff(map);
        doStuff(map);
        doStuff(map);
    }
}

Solution

  • You are a bit betwixt and between with this. What you are proposing won't end well. Assuming that you actually need a map of pointers...

    If the map has sole ownership of the objects contained within it, use std::map<std::unique_ptr <A>, int>. If it shares ownership with other parts of your code, use std::map<std::shared_ptr <A>, int>.

    Then, either way:

    • objects won't go away unexpectedly while still present in your map

    • objects will be cleaned up (or their reference count decremented) when you remove them from your map

    For your global objects, you can create them with std::make_unique or std::make_shared as appropriate, rather than using new. Then they can be managed the same way as everything else.