不能直接用 new + 裸指针管理组件化对象,因其缺乏所有权语义,易导致悬空指针、内存泄漏、use-after-free 和 double-delete;应优先使用 std::unique_ptr 配合 raii,仅在多系统共享且生命周期独立时谨慎使用 std::shared_ptr,并避免在 ecs 系统层暴露指针。

直接用裸指针管理组件化对象是高危操作,必须配合 RAII 和所有权语义约束,否则极易出现悬空指针或内存泄漏。
为什么不能直接用 new + raw pointer
游戏对象生命周期高度动态:实体可能在帧中创建又销毁,组件频繁挂载/卸载。裸指针不携带所有权信息,delete 时机一旦错位,就会导致:
-
Use-after-free:系统仍在访问已释放的Component实例 -
Double-delete:多个模块试图释放同一块内存 - 无法与
std::vector或std::unordered_map安全协作(容器析构时不会自动清理裸指针指向的内容)
典型错误场景:ComponentManager::Get() 返回 MyComponent*,调用方误以为可长期持有,下一帧该组件已被 Remove() —— 此时指针已悬空,但编译器不报错。
std::unique_ptr 是组件单所有权的默认选择
当组件只属于一个实体、且生命周期严格跟随实体时,std::unique_ptr 提供零成本抽象和确定性析构:
- 构造时用
std::make_unique<componenttype>(...)</componenttype>,避免裸new - 存储进容器时用
std::vector<:unique_ptr>></:unique_ptr>或std::unordered_map<entityid std::unique_ptr>></entityid> -
Get()方法应返回Component*(非拥有),而非转移所有权;若需临时移交,用std::move(ptr)显式表达意图 - 销毁实体时,容器析构自动触发所有
unique_ptr的delete,无需手动遍历
示例:
class ComponentManager {
std::unordered_map<entityid std::unique_ptr>> renderPool;
public:
void Add(EntityID id, RenderComponent comp) {
renderPool[id] = std::make_unique<rendercomponent>(std::move(comp));
}
RenderComponent* Get(EntityID id) {
auto it = renderPool.find(id);
return it != renderPool.end() ? it->second.get() : nullptr;
}
};</rendercomponent></entityid>
何时考虑 std::shared_ptr?小心循环引用
仅在以下明确场景使用:Component 需被多个系统(如 PhysicsSystem 和 AudioSystem)长期观察,且其生命周期独立于所属实体(例如:全局音效源、持久化存档组件)。
- 必须搭配
std::weak_ptr在观察方使用,避免循环引用(如System持有shared_ptr→Component又持有回调函数捕获该System) -
shared_ptr有原子计数开销,在高频更新路径(如每帧调用的Update())中应避免 - 禁止将
shared_ptr存入连续内存容器(如std::vector),会破坏缓存局部性——ECS 架构下这比引用计数开销更伤性能
ECS 中指针使用的真正陷阱:跨系统数据访问模式
很多人忽略的关键点:ECS 系统(System)本身不该持有任何组件指针,而应通过数据布局驱动访问:
- 不要写:
for (auto& ptr : physicsComponents) { ptr->Update(); } - 应该写:
for (size_t i = 0; i —— 直接操作 SoA(Structure of Arrays)连续数组 - 此时根本不需要指针;
positions.data()是float*,但它是只读视图,由ComponentPool<position></position>管理生命周期 - 唯一需要指针的地方是系统初始化时从
ComponentPool获取起始地址,之后全程用索引或迭代器推进
真正的复杂点不在“怎么用指针”,而在于“哪些地方根本不该出现指针”——ECS 的性能优势恰恰来自规避间接寻址。裸指针或智能指针只应在组件池管理器内部存在,绝不应穿透到系统逻辑层。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











