z6318
z6318

Reputation: 31

initialization of gtest fixture reference class member with a temporary

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

Answers (1)

Corristo
Corristo

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

Related Questions