注:本文以游戏开发应用为例进行讲解。
1. unique_ptr
:独占所有权
unique_ptr
是独占的,不能被复制或共享。它适用于游戏开发中那些需要唯一所有权的对象场景,例如游戏中的资源管理器或特定对象实例。以下是一个在游戏开发中的例子:
class Texture {};
class ResourceManager {
public:
std::unique_ptr<Texture> loadTexture(const std::string& file) {
return std::make_unique<Texture>();
}
};
在游戏中,资源(如纹理、模型)通常只需要加载一次,并且由资源管理器负责管理这些资源的生命周期。资源对象的所有权只属于资源管理器,其他地方不应该持有这些资源的所有权。在这里,ResourceManager
加载并管理Texture
对象,通过unique_ptr
确保每个纹理对象只能由资源管理器独占控制。
2. shared_ptr
:共享所有权
shared_ptr
适用于需要多个对象共享所有权的场景。当一个对象需要被多个地方引用时(如多个系统需要同时访问同一个游戏实体),shared_ptr
能够确保对象在最后一个引用被释放后才销毁。
在游戏开发中,通常有一个场景管理器(SceneManager
)和多个系统(例如物理系统、渲染系统),这些系统可能共享同一个实体。可以使用shared_ptr
来管理这些实体。
class GameEntity {
public:
GameEntity() { std::cout << "Entity created.\n"; }
~GameEntity() { std::cout << "Entity destroyed.\n"; }
};
void physicsSystem(std::shared_ptr<GameEntity> entity) {
// 物理系统使用实体
}
void renderSystem(std::shared_ptr<GameEntity> entity) {
// 渲染系统使用实体
}
int main() {
std::shared_ptr<GameEntity> entity = std::make_shared<GameEntity>();
physicsSystem(entity); // 物理系统共享该实体
renderSystem(entity); // 渲染系统也共享该实体
// entity会在最后一个引用离开作用域后自动释放
return 0;
}
这里,GameEntity
被多个系统共享管理,只有当所有系统都不再使用该实体时,实体才会被销毁。
3. weak_ptr
:避免循环引用
weak_ptr
与shared_ptr
配合使用,解决循环引用的问题。当两个对象相互引用时,会导致shared_ptr
之间的循环引用,造成内存无法释放。weak_ptr
不增加引用计数,常用于对象之间的弱引用。
假设在游戏中,一个父实体引用多个子实体,而每个子实体也需要访问父实体。这种双向引用可能会导致循环引用,可以通过weak_ptr
来避免。
class GameEntity;
class ChildEntity {
public:
std::weak_ptr<GameEntity> parent;
ChildEntity(std::weak_ptr<GameEntity> p) : parent(p) {}
};
class GameEntity {
public:
std::vector<std::shared_ptr<ChildEntity>> children;
void addChild(std::shared_ptr<ChildEntity> child) {
children.push_back(child);
}
};
int main() {
std::shared_ptr<GameEntity> parent = std::make_shared<GameEntity>();
std::shared_ptr<ChildEntity> child = std::make_shared<ChildEntity>(parent);
parent->addChild(child);
// 使用weak_ptr避免循环引用
return 0;
}
在这个例子中,ChildEntity
对GameEntity
的引用是通过weak_ptr
实现的,避免了循环引用的问题,从而正确管理内存。
4.总结
unique_ptr
:独占所有权,适合管理应用中的独占资源。shared_ptr
:共享所有权,适合多个系统或模块共同管理的对象。weak_ptr
:弱引用,适合避免循环引用的场景,通常与shared_ptr
配合使用。