C++中双shared_ptr容器对比unique_ptr+裸指针方案的优势咨询
我正在开发一款游戏,由Game类负责管理所有GameEntity实例并将其存储在容器中。为便于操作,Game类还需为特定类型的GameEntity(如PlayerGameEntity)设置专用容器。我设计了两种基于C++智能指针的实现方案,但尚不明确方案A(双shared_ptr容器)相比方案B(unique_ptr+裸指针)具备哪些优势。
方案A代码
std::vector<std::shared_ptr<GameEntity>> gameEntities; std::vector<std::shared_ptr<PlayerGameEntity>> players; void createPlayer() { std::shared_ptr<PlayerGameEntity> player = std::make_shared<PlayerGameEntity>(); gameEntities.emplace_back(player); players.emplace_back(player); }
方案B代码
std::vector<std::unique_ptr<GameEntity>> gameEntities; std::vector<PlayerGameEntity*> players; void createPlayer() { gameEntities.emplace_back(std::make_unique<PlayerGameEntity>()); players.emplace_back(dynamic_cast<PlayerGameEntity*>(gameEntities.back().get())); // 是否有更好的方式获取刚创建的实体指针? }
补充说明:Game类是所有实体的唯一所有者,会以裸指针形式将实体传递给其他系统。我理解方案B中从gameEntities移除GameEntity会标记其待销毁,这符合我的场景需求,现想了解方案A的优势所在。
方案A相对方案B的核心优势
彻底杜绝悬空指针:方案B的
players容器存储裸指针,一旦gameEntities里的unique_ptr销毁实体,players里的指针就会变成悬空指针,后续访问直接触发未定义行为。而方案A中两个容器的shared_ptr共享实体所有权,只有当所有指向该实体的shared_ptr都被移除时,实体才会销毁——哪怕误操作提前从gameEntities移除了玩家实体,只要players里还保留shared_ptr,实体就依然有效,不会出现崩溃问题。强类型安全,无动态转换开销:方案B必须用
dynamic_cast做类型转换,不仅有运行时性能损耗,还存在转换失败返回空指针的风险。方案A直接用shared_ptr<PlayerGameEntity>存储,从创建到存储全程强类型,无需动态转换,既高效又避免了类型错误。所有权扩展更灵活:虽然当前设定
Game是唯一所有者,但如果后续需求变更(比如异步任务需要临时持有实体),方案A的shared_ptr可以直接传递,无需修改核心架构;方案B的unique_ptr是独占所有权,只能通过裸指针传递,风险极高。无需手动维护容器同步:方案B中,从
gameEntities删除实体时必须手动同步移除players里对应的裸指针,否则会遗留悬空指针。方案A依靠引用计数自动管理生命周期,完全不需要这种同步操作,大幅减少了逻辑出错的概率。
方案B的小优化(针对指针获取)
你提到的方案B中获取指针可以避免dynamic_cast,优化代码如下:
void createPlayer() { auto player = std::make_unique<PlayerGameEntity>(); players.emplace_back(player.get()); gameEntities.emplace_back(std::move(player)); }
直接通过player.get()获取指针,无需动态转换,更高效安全。
内容的提问来源于stack exchange,提问作者Will F

