【问题标题】:Smart pointer gets prematurely deleted due to GTest teardown由于 GTest 拆解,智能指针被过早删除
【发布时间】:2019-07-18 08:27:22
【问题描述】:

我目前正在重构代码以使原始指针使用智能指针,并对此类进行测试,但遇到了智能指针被过早删除的问题

这是一个例子:

class SomeObjectType
{
public:
   void init()
   {
   }
};

class Helper
{
public:
    Helper()
    {
        std::cout << "Helper constructor" << std::endl;
       //some codes
    }
    ~Helper()
    {
        std::cout << "Helper destructor" << std::endl;
       //some codes
    }
    SomeObjectType* createObject()
    {
        return new SomeObjectType;
      //some codes
    }
    void destroyObject(SomeObjectType* obj)
    {
       //some codes
    }
};

class Base
{
public:
    Base()
    {
       helper = std::make_shared<Helper>();
    }
    ~Base()
    {
       destroyObject(obj);
    }
    void Init()
    {
       obj = createObject();
    }
    SomeObjectType* createObject()
    {
       return helper->createObject();
    }
    void destroyObject(SomeObjectType* obj)
    {
       helper->destroyObject(obj); // <-- I get the error here
    }

protected:
    std::shared_ptr<Helper> helper;

private:
    SomeObjectType* obj;

FRIEND_TEST(BaseTest , Init_handleSuccess);
};

在我的测试中:

class BaseTest : public ::testing::Test
{
public:
    void SetUp()
    {
        sut_ = std::make_unique<Base>();
        helperMock_ = std::make_shared<HelperMock>();
        //helperMock_ = new HelperMock;  //it works when I dont use smart pointers but of course there is a leak here
    }

protected:
    std::unique_ptr<Base> sut_;
    std::shared_ptr<HelperMock> helperMock_;
    //HelperMock* helperMock_; //it works when I dont use smart pointers but of course there is a leak here
};

TEST_F(BaseTest, Init_handleSuccess)
{
    auto obj = new SomeObjectType();
    sut_->helper.reset(helperMock_.get());
    EXPECT_EQ(S_OK, sut_->Init());
}

当我检查日志时,我看到这是发生的事情(按此顺序):

  • 调用测试设置

  • 调用基础构造函数

  • 调用了辅助构造函数

  • 测试拆解

  • 调用的辅助析构函数

  • 基析构函数调用

  • 基础析构函数尝试访问已被删除的helper = 崩溃!

所以基本上helper 指针在调用destroyObject() 之前已经被删除,因为它的生命与我的测试有关。因此,当我将测试更改为使用helper 的原始指针时,我没有得到双重删除,但后来它变成了泄漏,因为我根本没有删除helper :) 我该怎么做才能使helper 成为调用基类析构函数时还活着吗?

注意:我需要在 helper 的 createObject 中调用一些 API,这就是我嘲笑它的原因。我不能将帮助程序作为依赖项注入,这就是为什么我必须用sut_-&gt;helper.reset(helperMock_.get());“破解”它的原因@

【问题讨论】:

    标签: c++ pointers googletest gmock


    【解决方案1】:

    我相信这可能是你的问题...

    sut_->helper.reset(helperMock_);
    

    我什至不确定上面的代码是如何编译的,因为我认为reset 需要一个原始指针来获取 shared_ptr 的所有权。 (当您在 cmets 中更新时:您实际上是在使用 .get() 调用重置)。

    使用 shared_ptr 可能犯的最大错误是调用 .get() 或使用 * 运算符 - 并传递返回的原始指针来初始化另一个 shared_ptr。现在,您在同一个对象上获得了两个不同的引用计数会话。哪一组 shared_ptr 实例首先消失将删除该对象。让另一组 shared_ptrs 引用已删除的对象。

    将上面的内容替换为:

    sut_->helper = helperMock_;
    

    我假设 HelperMock 派生自 Helper。

    【讨论】:

    • 天啊,你是救生员。非常感谢,这行得通!
    • 我仍然不明白sut_-&gt;helper.reset(helperMock_); 是如何编译开始的。除非你真的使用helper.reset(*helperMock_);helper.reset(helperMock_.get());
    • 是的,我使用 helperMock.get() 进行重置。我的错,我只为这个问题创建了上面的代码,而不是我正在处理的实际代码。
    • 很高兴为您提供帮助 - 但是当您发布这样的问题时,您确实需要显示确切的代码。 .get() 从一开始就是提示。
    猜你喜欢
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 2011-08-02
    • 2011-10-04
    相关资源
    最近更新 更多