Gtest member initialization issue - c++

I'm having some issues understanding the following behavior of GTest.
When I have some members inside the fixture class that are initialized in the initializer list and I use them to initialize another member from the fixture, the following behavior happens.
In the first version the Copy Constructor from B is called and then the Parametrized Constructor of B.
In the second version first the Parametrized constructor and then the Copy Constructor is called.
My understanding is that the behavior should me similar in the first version and in the second version,
however the right behavior is seen only in the second version.
If I want to add some members like in the first version how should I do?
class ConfigEndpoint
{
ConfigEndpoint (const B& f_bar0 = B(),
const B& f_bar1 = B(),
const B& f_bar2 = B() )
};
ConfigEndpoint::ConfigEndpoint (const B& f_bar0 = B(),
const B& f_bar1 = B(),
const B& f_bar2 = B() )
: array {f_bar0, f_bar1, f_bar2} {}
Class B has two types of constructors:
// Default one:
B::B()
: m_space(MEMORY),
m_type(32BIT),
m_isConfigured(false)
{}
// Parametrized one:
B::B(int f_barSpace,
int f_barType)
: m_space(f_barSpace),
m_type(f_barType),
m_isConfigured(true)
{}
**//TestFixture -> version 1.**
class CConfigTest : public ::testing::TestWithParam<std::tuple<driverStartAddress, bool>>
{
public:
CConfigTest() :
bar0(MEMORY, 32BIT),
bar1(MEMORY, 32BIT),
bar2(MEMORY, 32BIT),
configEndpoint(bar0,
bar1,
bar2)
{ }
ConfigEndpoint configEndpoint;
const B bar0;
const B bar1;
const B bar2;
};
**//TestFixture -> version 2.**
class CConfigTest : public ::testing::TestWithParam<std::tuple<driverStartAddress, bool>>
{
public:
CConfigTest()
:
configEndpoint( B(MEMORY, 32BIT),
B(MEMORY, 32BIT),
B(MEMORY, 32BIT) )
{ }
ConfigEndpoint configEndpoint;
};

You haven't described what actually happens in both versions (i.e. what you expect vs. what you observe). At the first glance: you create bar[1|2|3] but you pass mock_bar[1|2|3] in the version no. 1.
On a side note: you have a bug in the class A: if you call it without parameters, you bind the temporary object to the const &A. This is fine on the stack, but not for the classes' members. And what is worse, you don't use it in tests (because you pass proper references there), so it will only fail in production or some integration test. See:
Does a const reference class member prolong the life of a temporary?

Related

Constructing objects with mutual references to each other

I've run into a bit of a chicken and the egg scenario.
Say I have these two classes
class A{
public:
A(B& );
private:
B& ref;
};
class B{
public:
B(A& );
private:
A& ref;
};
Is there any way for me to initialize them? Because the fields are references, I have to bind them in the member initializer list so they can never be null. However, I can't make either one of them without the other, so I can't even supply the references.
Currently, I have two thoughts. The first is that I can switch one of the fields to a raw pointer, that way I can just supply a nullptr and bind it later in a method. However this weakens my null safety so I don't really want to do that. My second thought was that I could just declare a variable without initializing it, so something like
A foo;
B bar(foo);
foo(bar);
where I just construct it later. Unfortunately, this calls a default constructor on the first line, which isn't provided, so this doesn't work.
So I would like some advice on getting my current ideas to work, or if there's a built-in mechanism in C++ for this that I don't know about.
Its a chicken and egg problem. You need an A to create a B and you need a B to create an A.
However, if you always create an A and a B together, then I would suggest, as already mentioned in a comment, to wrap them in a class. Then you can use the member initializer list:
struct B;
struct A {
A(B& b) : ref(b) {}
B& ref;
};
struct B {
B(A& a) : ref(a) {}
A& ref;
};
struct AB {
A a;
B b;
AB() : a(b),b(a) {}
};
Using the reference to member b before it has been initialized is fine as long as A only stores the reference and does not read from it or call methods.
However, once they are wrapped in the same class it is kind of pointless to have them store references to each other.
Moreover reference members have certain unpleasant implications (eg no copies). Consider if thats what you really like or if perhaps pointers are fine.
If you are trying to create a loop dependency then at least one of the members will need to be a pointer. But it is otherwise fully possible to have this work by using forward declarations.
class B;
extern B b;
class A
{
public:
A(B & b)
: b(b)
{
}
private:
B & b;
};
class B
{
public:
B(A & a)
: a(a)
{
}
private:
A & a;
};
A a(b);
B b(a);

Delegating copy constructor and const data initialization

I have a class A with lots of data members, some of which are constant. All data members have proper copy constructors, so I want to default a copy constructor of my class:
class A
{
public:
A() : a(1) {}
A(const A& op) = default;
private:
// ... Lots of constant and non-constant member data ...
const int a;
};
Then, I want to write a constructor which accepts a reference to A and a value which should initialize one of constant data members:
A(const A& op, const int a_);
Here op should be copied, and a should be initialized with a_ after that or instead of copying. I would like to avoid manual initialization of all data members by delegating to a copy constructor, but how to overwrite my const data member in this case?
For example:
// Illegal: constructor delegation can't be mixed with field initialization.
A(const A& op, const int a_) : A(op), a(a_) {}
// Illegal: attempt to assign constant member.
A(const A& op, const int a_) : A(op) { a = a_; }
// Hack. May lead to UB in some cases.
A(const A& op, const int a_) : A(op)
{
*(const_cast<int*>(&a)) = a_;
// ... or same tricks with memcpy ...
}
Obviously, all of these approaches are evil as they try to initialize a twice.
Another solution is to move all constant data to a base class and write all needed ctors, but it looks to verbose.
Is there a cleaner way to implement A(const A&, int a_)?
Unfortunately, C++ const field initialization is a very special case with specific syntax, so is constructor delegation, and the constructor syntax has no provision to mix them, so there can be no clean and neat solution here (at least for current C++ versions, maybe later...). The best I can imagine is:
class A
{
public:
A() : a(1) {}
A(const A& op):
const_field1(op.const_field1),..., a(op.a) // all const fields here
{ init() };
A(const A& op, int a_):
const_field1(op.const_field1),..., a(a)) // dup line at editor level
private:
void init(void) {
// init non const fields here
}
// ... Lots of constant and non-constant member data ...
const int a;
};
It does not make sense if you have only the copy ctor and one single additional one, but it could ease code maintenability if you have many additional ctors. It is a pity that only non const field setting can be factorized across different ctors with a private method, but C++ standard is like that.
What about a copy constructor with a full initialization list? Since your data is const, you will only be able to assign a value to it using initalization list.
A(const A& op, int a_) :
prop_a(op.prop_a_),
prop_b(op.prop_b_),
// continue for all members ...
a(a_) // except a
{
}

C++ How to Initialize member object?

Is there some way to initialize(?) member variable c of type C in the first part of the below example? Or must I use the new() method shown in the second part of the example?
Class B takes class A as an injected dependency. So does class C. Class B is additionally composed of class C.
How do I get the injected A to B's member C?
Part 1
class A { // ...; };
class C {
public:
C(A &a) : a(a) {} // constructor
};
// Does not work as is. Want to make compiler manage C lifetime.
class B {
public:
B(A &a); // constructor
C c(a); // member variable
};
// constructor
B::B(A &a) : a(a) {
}
Part 2
// Works, but requires programmer to manage C's lifetime.
class B {
public:
B(A &a); // constructor
C *c; // member variable
};
// constructor
B::B(A &a) : a(a) {
c = new C(a);
}
Several good answers below! My apologies for the confusing example. I have up-voted all of the good answers and questions. Unfortunately I can only mark one answer as the accepted answer, so I am choosing the first one which gave me the "ah-ha" moment in which I saw the solution to my real problem, which was more complex than my lame example here.
Member variables are initialized in constructor's initialization list (before body) so you need to do that:
B::B(A &a)
: c(a) // Calls constructor C(a) on member c
{}
You almost have it:
class B {
public:
B(A &a);
C c(a); //see note 1
};
B::B(A &a) : a(a) { //see note 2
}
Note 1:
There are two problems with C c(a); here:
a is not in scope. a only exists within the scope of the constructor, so c needs to be initialized from there.
Until C++11, non-static data member initializers (NSDMIs) were prohibited. Even in C++11, though, you must use an equals sign (C c = value;) or braces (C c{value};) when initializing an NSDMI.
Note 2:
You've almost got this right:
B::B(A &a) : a(a)
You're trying to initialize a data member called a with the argument given to the constructor. You actually want to initialize c like this, not a non-existent a:
B::B(A &a) : c(a)
The lifetime of c will be that of the instance of the B class. Using dynamic memory management is certainly not necessary.
"How do I get the injected A to B's member C?"
You can do so using B's constructor member initializer list
class B {
public:
B(A &a) : c(a) {
// ^^^^
}
C c; // <<< It's not possible to initialize members in their
// declaration.
};
The following:
C(A &a) : a(a) {}
will not compile since a (the first a in the initialization list) is not a member variable of C.
Same applies to the constructor of B.

C++ : const references and initialization order

I am wondering if I am using the good approach in the following :
I want to construct a parent class (class A), this class should own an instance of a given "Foo" class
I want the parent class to own a child class member (class B) and this member should have a reference to the foo member of the parent class.
The code below seems to works, however I am wondering whether I was just "lucky" that the compiler was sympathetic enough.
For clarity, I added comment and my question in the comments below.
Thanks !
struct Foo
{
std::string mValue;
};
class B
{
public:
B(const Foo & foo) : mFoo_External(foo) {}
private:
const Foo & mFoo_External; //this is an external reference to the member
//(coming from A)
};
class A
{
public:
//Here is the big question
//Shall I use :
// A(const Foo & foo) : mFoo(foo), mB(mFoo) {}
// or the declaration below
A(const Foo & foo) : mFoo(foo), mB(foo) {}
private:
//According to my understanding, the declaration
//order here *will* be important
//(and I feel this is ugly)
const Foo mFoo;
B mB;
};
void MyTest()
{
std::auto_ptr<Foo> foo(new Foo());
foo->mValue = "Hello";
A a( *foo);
foo.release();
//At this point (after foo.release()), "a" is still OK
//(i.e A.mB.mFooExternal is not broken, although foo is now invalid)
//
//This is under Visual Studio 2005 :
//was I lucky ? Or is it correct C++ ?
}
No, this is broken. Your mB will hold a reference to whatever you passed to the constructor of the A object, not to mFoo. Instead, you should say:
A(const Foo & foo) : mFoo(foo), mB(mFoo) { }
Note that mB is a copy of the constructor argument, and not a reference, so your MyTest function is fine.
Since you want your B object to hold a reference to the parent's member, you must initialize mB with mFoo not foo.
You are correct that the order of the member variables is important, since it determines the order of the initialization. It might come as a surprise that the order of the initializers in the constructor does not determine the order they are called! See Constructor initialization-list evaluation order.

Other way to prohibit a certain C++ class construction except than declaring the constructor private?

Say I have a class with some const reference member variable and I would like to forbid a certain type of construction. So I would declare the according constructor private. Of course, a constructor must initialise all const reference member variables of the class. Doing so, however, results in odd looking code:
class A {
};
class B {
B(const A& a): host(a) {}
private:
B():host(A()) {} // This is ugly and not needed !!
const A& host;
};
Is there another way to prohibit a certain construction type except than declaring the constructor private? I do not want to let the compiler write a constructor for me.
Simply don't define this:
B():host(A()) {} // This is ugly and not needed !!
That is, the following should do what you want to do:
class B {
B(const A& a): host(a) {}
private:
//B():host(A()) {} // This is ugly and not needed !!
const A& host;
};
The idea is if you've defined a constructor that takes parameter(s), then the default constructor is not generated by the compiler. That means, instances of the above class cannot be default created!
B b1; //error - needs default constructor which doesn't exist!
B b2(a); //ok - only way to create an instance!
C++11 solution
In C++11, you can explicity tell the compiler not to generate a particular constructor as:
struct B
{
B(const A &a) {}
B() = delete; //disable
};
Not only that. There is more to it, as explained below:
Now the interesting part
You can also selectively disable constructor(s) for selected types which makes delete more interesting. Consider this,
struct A
{
A (int) {}
};
Object of this class can be created not only with int argument, but any type which implicitly converts to int. For example,
A a1(10); //ok
A a2('x'); //ok - char can convert to int implicitly
B b;
A a3(b); //ok - assume b provides user-defined conversion to int
Now suppose, for whatever reason, I don't want the users of class A to create objects with char or class B , which fortunately or unfortunately can implicitly convert to int, then you can disable them as:
struct A
{
A(int) {}
A(char) = delete; //disable
A(const B&) = delete; //disable
};
Now here you go:
A a1(10); //ok
A a2('x'); //error
B b;
A a3(b); //error - assume (even if) b provides user-defined conversion to int
Online Demo : http://ideone.com/EQl5R
The error messages are very clear:
prog.cpp:9:5: error: deleted function 'A::A(char)'
prog.cpp:10:5: error: deleted function 'A::A(const B&)'
Just leave it out. As soon as you provide a custom constructor, no other constructor is auto-generated (except for a copy constructor).
If you want to forbid any construction – ending up with a class that has only static members – you can simply declare the constructor as private, and not define it. Such a class is very rarely useful in C++ (since you cannot create instances of it); the only purpose that I can think of is to implement trait classes:
template <typename T>
struct type_to_color {
static char const* value() { return "blue"; }
private:
type_to_color();
};
template <>
struct type_to_color<int> {
// Integers are red!
static char const* value() { return "red"; }
private:
type_to_color();
}
char const* char_color = type_to_color<char>::value();
char const* int_color = type_to_color<int>::value();
However, this is extremely uncommon: trait classes are abundant in C++ but they never declare their constructors as private, it’s just assumed that everybody knows not to instantiate them.
I'll post the C++11 solution: delete the constructor.
class B {
B() = delete;
B(const A& a): host(a) {}
private:
const A& host;
};
As Konrad Rudolph sayd: as soon you provide a custom constructor, no other constructor is auto-generated (except for a copy constructor).
Therefore, other options are:
Declare the constructor private (so that you can't inherit from your class), but do not provide a definition:
class B {
public:
B(const A& a): host(a) {}
private:
B(); // not implemented!
const A& host;
};
Or in C++11, as R. Martinho Fernandes says:
class B {
public:
B() = delete;
B(const A& a): host(a) {}
private:
const A& host;
};