C++ 如何将std::shared_ptr管理对象的原始this指针转为shared_ptr使用
解决方案
以下是两种适配你需求的常用实现方案,可根据你的业务对生命周期安全和性能的要求选择:
方案1:保留裸指针存储(性能最优,适合生命周期可控场景)
该方案改动最小、无额外性能开销,只要你能保证所有Intersection实例的使用周期,都短于存储对象的world vector的生命周期即可使用:
- 第一步:让
IHittable公共继承std::enable_shared_from_this<IHittable>,示例代码:
class IHittable : public std::enable_shared_from_this<IHittable> { public: virtual Intersection intersects(const Ray& ray) const = 0; virtual ~IHittable() = default; };
- 第二步:给
Intersection新增支持std::shared_ptr<IHittable>的构造函数,满足你要求的调用写法:
class Intersection { public: Intersection(double t, IHittable * object) : t_(t), object_(object) {} // 新增构造函数,支持直接传入shared_ptr构造 Intersection(double t, const std::shared_ptr<IHittable>& object) : t_(t), object_(object.get()) {} [[nodiscard]] double t() const { return t_; } [[nodiscard]] IHittable * object() const { return object_; } private: double t_; IHittable * object_ = nullptr; };
- 第三步:派生类的
intersects方法可以直接用this构造返回,原有代码不需要修改;如果想要更统一的写法,也可以用shared_from_this().get()替代this,效果完全一致。
如果你的场景里world会在程序运行全程存在,直到所有求交计算结束才销毁,该方案是最优选择,遍历world调用intersects的效率和裸指针vector完全一致。
方案2:Intersection存储shared_ptr(生命周期安全,适合复杂场景)
如果你的业务逻辑中存在world可能提前释放,或者Intersection需要脱离world长期留存的场景,可以把Intersection内部的存储改成shared_ptr,完全避免悬空指针问题:
- 第一步:同样让
IHittable继承std::enable_shared_from_this<IHittable> - 第二步:修改Intersection的定义:
class Intersection { public: Intersection(double t, std::shared_ptr<IHittable> object) : t_(t), object_(std::move(object)) {} [[nodiscard]] double t() const { return t_; } // 可根据需要返回裸指针或者shared_ptr的常量引用 [[nodiscard]] IHittable * object() const { return object_.get(); } [[nodiscard]] const std::shared_ptr<IHittable>& shared_object() const { return object_; } private: double t_; std::shared_ptr<IHittable> object_ = nullptr; };
- 第三步:修改派生类的
intersects返回逻辑:
Intersection Sphere::intersects(const Ray & ray) { double x = ...; // 原有求交计算逻辑不需要改动 return {x, shared_from_this()}; }
该方案的优势是完全不需要操心生命周期问题,只要Intersection还存在,对应的Hittable对象就不会被释放,唯一的额外开销是shared_ptr的引用计数增减,对于绝大多数图形学场景来说这点性能损失可以忽略不计。
注意:使用
std::enable_shared_from_this的前提是,所有IHittable的实例都必须由std::shared_ptr管理,不能在栈上分配IHittable的派生类实例,也不能用裸指针创建的实例调用shared_from_this(),否则会触发未定义行为。你的场景里所有对象都通过std::make_shared创建并存入worldvector,完全符合这个要求,不会有问题。
内容的提问来源于stack exchange,提问作者a a
相关产品推荐
相关产品推荐

