GMock中使用EXPECT_CALL为何触发std::unique_ptr管理的mock泄漏报错
问题原因
这个泄漏报错的触发逻辑非常明确:
- 只要你对Mock对象调用过
EXPECT_CALL设置期望,gMock就会把该对象地址加入全局检测列表,在对象析构时自动校验期望是否满足,程序退出时会扫描列表里所有还没析构的Mock对象,抛出你看到的泄漏错误。 - 你代码里通过
std::move把mock_client的所有权转移给了栈上的Runner对象,按正常逻辑,测试用例结束时Runner析构,应该会自动释放持有的unique_ptr,进而析构Mock对象。现在报泄漏,唯一的原因就是**Runner拿到指针所有权后,没有在自身生命周期结束时正确释放指针**。
常见的错误实现包括:- Runner构造函数接收unique_ptr后,调用
release()拿到裸指针存为成员,没有在析构函数里手动delete裸指针 - Runner把传入的指针转交给了全局/静态生命周期的容器持有,自身不负责释放
- Runner存在基类析构函数非虚、析构逻辑异常跳过等问题,导致持有的指针没有被释放
- Runner构造函数接收unique_ptr后,调用
- 为什么移除
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
相关产品推荐
相关产品推荐

