You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类C如何处理存储的类D对象引用的有效性问题

类C处理D对象引用有效性的最优方案

问题背景

类C作为库组件,持有存储D对象指针的vector,当调用方的D对象超出作用域销毁后,需要避免C访问悬垂指针。

现有方案分析

方案1:D析构时主动从C的列表中移除

  • 弊端:这种设计会让D和C产生强耦合,D必须知晓C的内部存储结构(比如_list),违反了单一职责原则和封装性。如果后续C的存储结构变更(比如从vector改成unordered_set),所有D类的相关代码都要修改,维护成本极高。另外,若存在多个C实例持有同一个D的指针,D的析构逻辑会变得复杂,容易出现遗漏或错误。

方案2:改用weak_ptr存储

  • 可行性:这是生产环境中常用的成熟方案。将vector<D*>改为vector<weak_ptr<D>>,每次访问前调用weak_ptr::lock()获取shared_ptr,如果lock()返回空,说明对象已销毁,直接跳过即可。
  • 注意事项:需要调用方在创建D对象时使用shared_ptr(比如auto d = make_shared<D>()),再将weak_ptr传递给C。weak_ptr不会增加引用计数,因此不会延长D对象的生命周期,同时能安全检测对象是否存活。

优化后的示例代码

#include <memory>
#include <vector>
#include <algorithm>
#include <cstdio>

struct D
{
    ~D()
    {
        printf ("~D()\n");
    }
};

class C
{
    std::vector<std::weak_ptr<D>> _list;

public:
    void add(std::weak_ptr<D> dObject)
    {
        _list.push_back(dObject);
        printf ("Adding D => size = %ld\n", _list.size());
    }

    // 遍历并处理所有有效对象,同时清理失效引用
    void processValidObjects()
    {
        // 先清理已失效的weak_ptr,避免列表冗余膨胀
        _list.erase(std::remove_if(_list.begin(), _list.end(),
            [](const std::weak_ptr<D>& wp) { return wp.expired(); }),
            _list.end());

        for (auto& wp : _list)
        {
            if (auto sp = wp.lock())
            {
                // 此时sp指向的D对象一定有效,可安全访问
                printf("Processing valid D object\n");
            }
        }
    }

    ~C()
    {
        printf ("~C()\n");
    }
};

int main()
{
    C c1;
    {
        auto d1 = std::make_shared<D>();
        c1.add(d1);
    }

    printf ("----out of scope---\n"); 
    auto d2 = std::make_shared<D>();                    
    c1.add(d2);

    c1.processValidObjects();
}

额外建议

  • 如果调用方无法使用shared_ptr(比如D对象是栈上分配的),可以采用观察者模式:C作为观察者,D作为被观察者,D在析构时通知所有持有它引用的C实例移除自身。这种方式比方案1更解耦,D只需要维护一个观察者列表,不需要知晓C的内部存储细节。
  • 定期清理C中已失效的引用(比如在add或processValidObjects方法中),避免容器积累大量无效指针,影响后续遍历性能。

内容的提问来源于stack exchange,提问作者xyf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 06:25:29