Reputation: 31
Just learning gtest and have hit something concerning object lifetimes I don't get. Given this test fixture initializing a class member reference with a temporary:
#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());
}
the first test passes and the second test fails with the reference uninitialized.
But if I test the exact same Base and Foo code with my own test class and access the check() method through main:
// 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;
}
the reference is valid. The only way I can get the gtest version to pass is initializing the reference with an lvalue.
I'm using gtest 1.8.0 and building with g++ -std=c++17 -g -Wall -O3.
From cppreference: a temporary bound to a reference member in a constructor initializer list persists only until the constructor exits, not as long as the object exists. (note: such initialization is ill-formed as of DR 1696). (until C++14)
Is this a gtest version/c++ version mismatch? Am I on the right track here to understand this?
Upvotes: 1
Views: 1420
Reputation: 5510
The "until C++14" part of cppreference you quoted doesn't mean that from C++17 onwards the lifetime of the temporary no longer ends when the constructor exits, quite to the contrary: [class.base.init/8] now states that
A temporary expression bound to a reference member in a mem-initializer is ill-formed.
That is you're no longer allowed to even bind the reference member to a temprorary. I'm surprised your code even compiles, seems like GCC isn't fully conforming here.
Upvotes: 1