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

2019-07-07 00:23发布

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.

2条回答
成全新的幸福
2楼-- · 2019-07-07 00:58

...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; 
查看更多
来,给爷笑一个
3楼-- · 2019-07-07 01:02

Absolutely.
Class types have constructors and destructors.
They are called implicitly during instantiation and at the end of the variable's lifetime.

This concept is known as RAII, and its what smart pointers leverage for automatic memory management.

It depends on your use case, but you may consider using unique pointers as well:

#include <iostream>
#include <memory>
#include <map>

struct Foo{

  Foo(){
    std::cout << "construct\n";
  }

  ~Foo(){
    std::cout << "destruct\n";
  }
};

int main(){
  std::map<int, std::unique_ptr<Foo>> m;

  //prints construct 3 times
  m.emplace(1,std::make_unique<Foo>());
  m.emplace(2,std::make_unique<Foo>());
  m.emplace(3,std::make_unique<Foo>());

  //prints destruct 3 times
  m.clear();
}
查看更多
登录 后发表回答