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

GMock中使用EXPECT_CALL为何触发std::unique_ptr管理的mock泄漏报错

问题原因

这个泄漏报错的触发逻辑非常明确:

  1. 只要你对Mock对象调用过EXPECT_CALL设置期望,gMock就会把该对象地址加入全局检测列表,在对象析构时自动校验期望是否满足,程序退出时会扫描列表里所有还没析构的Mock对象,抛出你看到的泄漏错误。
  2. 你代码里通过std::move把mock_client的所有权转移给了栈上的Runner对象,按正常逻辑,测试用例结束时Runner析构,应该会自动释放持有的unique_ptr,进而析构Mock对象。现在报泄漏,唯一的原因就是**Runner拿到指针所有权后,没有在自身生命周期结束时正确释放指针**。
    常见的错误实现包括:
    • Runner构造函数接收unique_ptr后,调用release()拿到裸指针存为成员,没有在析构函数里手动delete裸指针
    • Runner把传入的指针转交给了全局/静态生命周期的容器持有,自身不负责释放
    • Runner存在基类析构函数非虚、析构逻辑异常跳过等问题,导致持有的指针没有被释放
  3. 为什么移除EXPECT_CALL就不报错?因为gMock默认只对设置过期望的Mock对象开启泄漏检测。如果从来没给Mock加过期望,哪怕对象真的泄漏了,gMock也不会提示——这不是代码没问题,只是检测没触发而已。
修复方案
  • 优先修正Runner的所有权逻辑:既然构造函数接收std::unique_ptr类型参数,就代表契约上明确要求Runner持有指针所有权、负责对象释放。最稳妥的实现是用std::unique_ptr类型的成员变量接收move进来的指针,不需要手动写delete逻辑,靠unique_ptr自动析构就能正确释放Mock对象。
    会泄漏的错误实现参考:
    class Runner {
    public:
      Runner(std::unique_ptr<Client> c, std::unique_ptr<Evaluator> e) {
        client_ = c.release();
        evaluator_ = e.release();
      }
    private:
      Client* client_;
      Evaluator* evaluator_;
      // 析构函数未delete两个裸指针,必然泄漏
    };
    
    正确实现参考:
    class Runner {
    public:
      Runner(std::unique_ptr<Client> c, std::unique_ptr<Evaluator> e)
        : client_(std::move(c)), evaluator_(std::move(e)) {}
    private:
      std::unique_ptr<Client> client_;
      std::unique_ptr<Evaluator> evaluator_;
    };
    
  • 仅当你确实需要让Mock对象以全局单例等形式长生命周期存活、不会在测试结束前析构时,才可以用testing::Mock::AllowLeak(mock_client.get())临时关闭该对象的泄漏检测,不要用这个方法掩盖真实的所有权bug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:18:43