所以我的理解是,当对象的最后一个剩余所有者被销毁或重新分配时,shared_ptr会自动从内存中释放出来(看起来好得令人难以置信?),当许多实例可能共享同一个对象时,它很有用。正确的吗?
所以在我的情况下,我正在制作一个2d平铺世界,所以我在屏幕上绘制了许多相同的纹理。
我有
std::map<int, shared_ptr<Tile>> Tiledb;
存储所有瓷砖。我的想法是只加载一次纹理,然后我可以根据需要多次渲染它。然后一旦比赛结束,我就打电话给
Tiledb.clear();
这会自动释放所有内存吗?我很习惯于常规指针,这看起来很神奇,坦率地说,太容易了。我认为它是如何工作的我错了吗?使用shared_ptrs有什么缺点吗?哈哈,我感到很惊讶。
感谢您提供任何信息。
答案 0 :(得分:7)
...当许多实例可能共享同一个对象时,它很有用。正确的吗?
不完全是。当许多实例可能拥有同一个对象时,它很有用。共享不足以证明使用std::shared_ptr
是合理的,因为使用它肯定会有一些开销。
创建动态资源时,您需要考虑所有权即。 谁负责删除?应该负责删除资源的对象应该使用某种智能指针(或容器)来管理资源。
如果只有一个对象负责决定何时必须删除资源,则使用std::unique_ptr
。如果其他对象/函数需要共享访问资源但永远不负责删除它,那么将它们传递给引用或原始指针到资源。
使用std::shared_ptr
的时间是当您无法知道哪些共享资源的对象将是需要删除它的对象时。在这种情况下,每个对象应该通过持有std::shared_ptr
来保存资源的所有权。
即使多个对象通过std::shared_ptr
共享所有权,他们仍应仅传递引用或原始指针不需要所有权权利的对象/功能。
在willy-nilly(不需要它们)的情况下传递std::stared_ptr
的另一个问题是它们可能会遇到 Java内存泄漏问题。这就是对象永远不会死的原因,因为对它们的一些引用仍然存在于软件的忘记部分。他们可以逐渐积累并消耗你的记忆。
通常,您应该更喜欢将资源保存在容器中,例如std::vector
或std::map
:
std::map<int, Tile> Tiledb;
容器管理Tile
的销毁,因此不需要智能指针。
但是,如果您使用多态 Tile
对象,则需要使用指针存储它们。为此,我更喜欢使用std::unique_ptr
:
// When the Tiles are no longer needed after the map is destroyed
std::map<int, std::unique_ptr<Tile>> Tiledb;
如果地图被销毁后其他对象需要继续访问Tile
个对象,那么std::shared_ptr
可能是合适的:
// only when Tiles need to keep living after the map is destroyed.
std::map<int, std::shared_ptr<Tile>> Tiledb;
答案 1 :(得分:1)
绝对。
类类型具有构造函数和析构函数
它们在实例化期间和变量的生命周期结束时被隐式调用。
这个概念被称为RAII,它的智能指针用于自动内存管理。
这取决于您的用例,但您也可以考虑使用唯一指针:
#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();
}