For the sake of RAII, I want to keep my class members as value objects, but I also want to pass pointers to other objects into their constructors, to ensure they are initialized right away.
I'm initializing them using the constructor initialization list, but I'm not sure if it is okay initialize class members with pointers to other class members.
The following code compiles and works as expected for me in XCode, with the Apple LLVM 5.1 compiler, but is this defined behavior that I can use and trust for all compilers? And, is this good practice in general, or something to avoid? Is there another way to achieve this, other than an init()
function?
class Foo {
public:
int value;
Foo() {}
void woot() {
std::cout << "A Foo says WOOT my value is: " << value << std::endl;
}
};
class Bar {
public:
Foo* foo;
int value;
Bar( Foo* f ) : foo(f) {
foo->value = 66;
foo->woot();
}
void woot() {
std::cout << "A Bar says WOOT my value is: " << value << std::endl;
}
};
class Boo {
public:
Foo* foo;
Bar* bar;
int value;
// Passing members into constructors of other members:
Boo( Foo* f, Bar* b ) : foo(f), bar(b) {
foo->value = 77;
foo->woot();
bar->value = 88;
bar->woot();
}
};
class Yaa {
public:
Foo foo;
Bar bar;
Boo boo;
Yaa() : bar(&foo), boo(&foo, &bar) {
woot();
}
void woot() {
std::cout << "A Yaa says WOOT, my children say woot:" << std::endl;
foo.woot();
bar.woot();
}
};
void testInitialisation() {
Yaa f;
}
// ...
testInitialisation();
// Output:
// A Foo says WOOT my value is: 66
// A Foo says WOOT my value is: 77
// A Bar says WOOT my value is: 88
// A Yaa says WOOT, my children say woot:
// A Foo says WOOT my value is: 77
// A Bar says WOOT my value is: 88
EDIT / NOTE: After accepting @Wes Hardaker's answer, I took his advice and did some more reading on initialization order. I believe my original confusion came about after reading a "Best Practices" note in "The C++ Primer", [Lippman, Lajoie, & Moo]:
...When possible, avoid using members to initialize other members.
Later, I had this idea in my mind that it was wrong, but after reading the chapter again I realise that this is perfectly legal, although should be used with caution. The book is actually warning about a potential danger when using members to initialize other members. The order of initialisation is determined by the order in which the members are declared in the class, not by their order in the initialization list. This means that you can potentially pass an undefined member into another, if you get the order backward.
So it's fine if you are careful, but I guess it could come back and bite you (or someone else using your code) later.