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

Google Mock搭配unique_ptr使用时出现mock对象内存泄漏如何解决

问题根因

这个报错是GoogleTest的泄漏检测机制触发的:程序退出前你创建的MockDerivedClass实例从未执行析构,属于明确的mock对象生命周期问题,结合你贴的代码,触发原因基本是以下两类:

  • 所有权接管逻辑错误:你虽然通过std::move(mockClass)把mock对象的unique_ptr传给了CallingClass构造函数,但如果构造函数实现中没有将传入的unique_ptr移动赋值给成员变量drivedClass,甚至调用release()拿到裸指针后直接丢弃、没有在析构时手动释放,mock对象的内存就永远不会被回收,自然不会触发析构。
  • 不完整类型析构的未定义行为:如果CallingClass使用编译器自动生成的默认析构,且析构实例化的位置看不到DerivedClass/MockDerivedClass的完整定义,std::unique_ptr的默认删除器无法正确触发派生类的虚析构逻辑,最终导致Mock对象的析构不被执行,被gtest判定为泄漏。
    另外你当前的代码设计本身有缺陷:CallingClass直接依赖具体实现类DerivedClass而非抽象基类Base,违反依赖倒置原则,后续替换mock、切换实现都会有不必要的耦合。
根本修复方案(推荐)

不要上来就用屏蔽报错的接口,按以下步骤调整可以彻底解决问题:

  1. 修正依赖关系,将CallingClass的依赖从具体类DerivedClass改成抽象基类Base,本来基类已经定义了纯虚接口,完全不需要绑定具体实现:
    class CallingClass
    {
    public:
        CallingClass(std::unique_ptr<Base> drivedClass);
        void callSomthing(); // 你测试代码中调用了该方法,记得补声明
        ~CallingClass();
    private:
        std::unique_ptr<Base> drivedClass;
    };
    
    构造函数实现通过初始化列表明确接管所有权,不要随意调用release()转裸指针:
    CallingClass::CallingClass(std::unique_ptr<Base> drivedClass)
        : drivedClass(std::move(drivedClass))
    {}
    
  2. 显式定义CallingClass的析构,将析构实现放在能看到Base、DerivedClass、MockDerivedClass完整定义的编译单元中(比如测试文件、类对应的cpp文件),直接用默认实现即可:
    // 放在所有类完整定义之后
    CallingClass::~CallingClass() = default;
    
    这一步可以避免编译器在不完整类型上下文生成默认析构导致的unique_ptr删除UB。
  3. 所有类定义末尾补全分号,你贴的三段类定义末尾都漏了分号,正常情况下这会直接导致编译失败,如果是贴代码时遗漏可忽略。

调整完成后,TEST用例执行到作用域结束时,栈上的callingClass会正常析构,内部持有的unique_ptr会逐层调用派生类的析构函数,Mock对象被正常回收,gtest的泄漏报错自然消失,同时mock上的期望调用校验也会在析构时正常执行。

临时屏蔽方案(不推荐)

如果你确实需要保留当前的所有权设计、暂时不修复泄漏,可以在创建mock对象后调用gtest提供的接口显式允许该对象泄漏,直接屏蔽报错:

TEST(TestGroup, Test1)
{
    std::unique_ptr<MockDerivedClass> mockClass(new MockDerivedClass());
    EXPECT_CALL(*mockClass, target_method()).WillRepeatedly(Return(1));
    testing::Mock::AllowLeak(mockClass.get()); // 新增这行即可
    CallingClass callingClass(std::move(mockClass));
    callingClass.callSomthing();
    
    // EXPECT_EQ处填入你实际需要断言的业务逻辑结果即可
}

注意这个方法只是关闭了对应mock对象的泄漏检查,并没有解决实际的内存泄漏问题,mock对象上的调用期望也不会在析构时被校验,仅适用于确实需要故意泄漏对象的特殊场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 15:54:17