Google 测试中的 RAII 内存损坏
RAII memory corruption in Google Test
我已经实现了 C 指针的自动删除器。该代码在测试程序中有效,但是当我在 Google 测试中使用该代码时,奇怪的事情发生了。我不明白为什么。我写过未定义的行为吗?还是 Google 测试会以某种方式干扰?
下面的代码,如果宏 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();
}
这是未定义的行为:
您正在将构造函数参数中的 std::initializer_list
复制到 class 成员中。
复制 std::initializer_list
不会复制其基础元素。因此,在离开构造函数后,无法保证 vals_
包含任何有效内容。
改用 std::vector
作为成员,并从初始化列表构造它。
我不确定你对这个守卫的意图,但使用 std::unique_ptr
.
可能会更容易
我已经实现了 C 指针的自动删除器。该代码在测试程序中有效,但是当我在 Google 测试中使用该代码时,奇怪的事情发生了。我不明白为什么。我写过未定义的行为吗?还是 Google 测试会以某种方式干扰?
下面的代码,如果宏 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();
}
这是未定义的行为:
您正在将构造函数参数中的 std::initializer_list
复制到 class 成员中。
复制 std::initializer_list
不会复制其基础元素。因此,在离开构造函数后,无法保证 vals_
包含任何有效内容。
改用 std::vector
作为成员,并从初始化列表构造它。
我不确定你对这个守卫的意图,但使用 std::unique_ptr
.