【问题标题】:RAII memory corruption in Google TestGoogle 测试中的 RAII 内存损坏
【发布时间】:2016-10-13 04:45:33
【问题描述】:

我已经为 C 指针实现了一个自动删除器。该代码在测试程序中有效,但是当我在 Google Test 中使用该代码时,会发生奇怪的事情。我不明白为什么。我写过未定义的行为吗?还是 Google Test 会以某种方式干扰?

下面的代码,如果宏 ASSERT_THAT 被注释掉,打印:

i1 = 0x8050cf0
i2 = 0x8050d00
got: 0x8050cf0
got: 0x8050d00
go delete: 0x8050cf0
go delete: 0x8050d00

创建了两个指针,守卫获取这些指针,然后删除它们。到目前为止,完全符合要求。

如果宏被激活,结果是:

i1 = 0x8054cf0
i2 = 0x8054d00
got: 0x8054cf0
got: 0x8054d00
go delete: 0x8054c01

由于某种原因,代码删除了另一个指针,然后删除了一个指针。我完全糊涂了。你能帮忙找出问题吗?

#include <iostream>
#include <gmock/gmock.h>

using namespace testing;

class Scope_Guard {
public:
  Scope_Guard(std::initializer_list<int*> vals)
    : vals_(vals)
    {
    for (auto ptr: vals_) {
      std::cerr << "got: " << ptr << std::endl;
    }
  }
  ~Scope_Guard() {
    for (auto ptr: vals_) {
      std::cerr << "go delete: " << ptr << std::endl;
      delete ptr;
    }
  }
  Scope_Guard(Scope_Guard const& rhs) = delete;
  Scope_Guard& operator=(Scope_Guard rhs) = delete;
private:
  std::initializer_list<int*> vals_;
};

TEST(Memory, GuardWorksInt) {
  int* i1 = new int(1);
  int* i2 = new int(2);
  std::cerr << "i1 = " << i1 << std::endl;
  std::cerr << "i2 = " << i2 << std::endl;
  Scope_Guard g{i1, i2};

  ASSERT_THAT(1, Eq(1)); // (*)
}

int main(int argc, char** argv) {
  InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

【问题讨论】:

    标签: c++ memory googletest raii


    【解决方案1】:

    这是未定义的行为:

    您正在将 std::initializer_list 从构造函数参数复制到类成员中。

    复制std::initializer_list 不会复制其底层元素。因此,离开构造函数后,不能保证vals_ 包含任何有效的内容。

    对成员使用std::vector,并从初始化列表构造它。

    我不确定你对这个守卫的意图,但使用std::unique_ptr 可能会更容易。

    【讨论】:

    • "我不知道你为什么写 delete ptr;那里?"在构造函数中也获得输出是一个复制/粘贴错误。谢谢你的评论,我已经编辑了这个问题。
    猜你喜欢
    • 2012-06-13
    • 2013-06-13
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2016-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多