刚刚学习 gtest,遇到了一些我不明白的关于对象生命周期的问题。鉴于此测试夹具使用临时初始化类成员引用:
#include "gtest/gtest.h"
struct Base {
bool check() const {
if (str_ == "test") return true;
return false;
}
private:
std::string str_{"test"};
};
struct Foo : public Base {};
class FooTest : public ::testing::Test {
protected:
FooTest() : b{Foo{}} {}
const Base& b;
};
TEST_F(FooTest, RefOne) {
const Base& x{Foo{}};
ASSERT_TRUE(x.check());
}
TEST_F(FooTest, RefTwo) {
ASSERT_TRUE(b.check());
}
第一个测试通过,第二个测试失败,引用未初始化。
但是如果我用我自己的测试类测试完全相同的 Base 和 Foo 代码并通过 main 访问 check() 方法:
// same Base and Foo code
struct Tester {
Tester() : b{Foo{}}
const Base& get() const {
return b;
}
private:
const Base& b;
};
int main() {
Tester t;
if (t.get().check()) std::cout << "Pass." << std::endl;
}
引用有效。我能让 gtest 版本通过的唯一方法是用左值初始化引用。
我正在使用 gtest 1.8.0 并使用 g++ -std=c++17 -g -Wall -O3 进行构建。
来自 cppreference:绑定(bind)到构造函数初始化列表中的引用成员的临时绑定(bind)仅持续到构造函数退出,而不是只要对象存在。 (注意:从 DR 1696 开始,这种初始化是错误的)。 (直到 C++14)
这是 gtest 版本/c++ 版本不匹配吗?我的理解是否正确?
最佳答案
您引用的 cppreference 的“直到 C++14”部分并不意味着从 C++17 开始,当构造函数退出时,临时对象的生命周期不再结束, 恰恰相反: [class.base.init/8]现在说
A temporary expression bound to a reference member in a mem-initializer is ill-formed.
也就是说,您不再被允许将引用成员绑定(bind)到临时成员。 我很惊讶你的代码甚至编译,似乎 GCC 在这里不完全符合。
关于c++ - 使用临时的 gtest fixture 引用类成员的初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52355813/