Search code examples
c++c++11shared-ptrsmart-pointers

New to c++11 features, proper use of shared_ptr?


So my understanding is that a shared_ptr automatically deallocates from memory when the last remaining owner of the object is destroyed or reassigned, (Seems too good to be true?) and it's useful when many instances may be sharing the same object. Correct?

So in my case, I'm making a 2d tiled world, so I'm drawing many of the same texture to the screen.

I have

std::map<int, shared_ptr<Tile>> Tiledb;

to store all the tiles. The idea is to only load the texture in once and then i can render it as many times as I want. Then once the game ends I call

Tiledb.clear();

And this frees all the memory automatically? I'm so conditioned to regular pointers that this just seems magical, and quite frankly, too easy. Am I wrong in thinking this is how it works? Is there any downside to using shared_ptrs? I'm just amazed that this exists haha.

Thanks for any information.


Solution

  • ...it's useful when many instances may be sharing the same object. Correct?

    Not exactly. It is useful when many instances may be owning the same object. Sharing is not enough to justify using a std::shared_ptr as there is certainly some overhead to using it.

    When you create dynamic resources you need to think about ownership ie. who is responsible for deleting it? The object that should be responsible for deleting the resource should manage the resource using some kind of smart pointer (or a container).

    If only one object is responsible for deciding when the resource must be deleted then use a std::unique_ptr. If other objects/functions need to share access to the resource but will never be responsible for deleting it, then pass them a reference or a raw pointer to the resource.

    The time to use a std::shared_ptr is when you can not know which of the objects that are sharing the resource will be the one that needs to delete it. In that case each object should hold ownership of the resource by holding a std::shared_ptr.

    And even when several objects share ownership through a std::shared_ptr they should still only pass a reference or a raw pointer to objects/functions that do not need ownership rights.

    Another problem with passing std::stared_ptr round willy-nilly (where they are not needed) is that they can suffer from the Java memory leak problem. That is when objects never die because some reference to them remains in a forgotten part of the software. They can gradually accumulate and eat away your memory.

    Typically you should prefer keeping your resources in a container like a std::vector or a std::map:

    std::map<int, Tile> Tiledb;
    

    The container manages the destruction of the Tile so no need for a smart pointer.

    If, however, you were using polymorphic Tile objects then you would need to store them using a pointer. For this prefer to use std::unique_ptr:

    // When the Tiles are no longer needed after the map is destroyed
    std::map<int, std::unique_ptr<Tile>> Tiledb;
    

    If other objects need to keep accessing the Tile objects after the map is destroyed then a std::shared_ptr may be appropriate:

    // only when Tiles need to keep living after the map is destroyed.
    std::map<int, std::shared_ptr<Tile>> Tiledb;