Class constructor question.

If I use an initializer list to initialize most of my member variables, but I have one data member that needs to be initilized through another function, what would be the proper way to do this and keep the compiler happy? Below is an example of what I'm currently doing, and curious if this is considered "acceptable" by C++ standards and best practices.

Is mixing initialization methods OK to do?

1
2
3
4
5
Text::Text(int fontSize, const char* text) : _fontPath("Assets/Fonts/8BIT.ttf"), _fontValue(text), _fontSize(fontSize), _fontColor({ 255, 255, 255, 255 })
{
    _textTexture = loadFont(_fontPath, _fontSize, _fontValue, _fontColor);
    SDL_QueryTexture(_textTexture, NULL, NULL, &_textRect.w, &_textRect.h);
}


As you can see I use the initializer list to initialize the majority of the member variables, but because _textTexture is initailized through the loadFont() function, I figured it's best to put that inside the constructor itself, is this a common way of doing things if you'd rather use an initializer list, but then have a member variable that needs to call another function?
Last edited on
The initializer list exists for two reasons:

1. some members can't be initialized in any other way:
a. Reference members
b. non-static const members
c. member classes with no default ctor
d. base classes with no default ctor

2. it can be more efficient
e.g.
Object(string s) { _s = s; }
member string _s is first constructed with string's default ctor and then assigned the value of s.
Object(string s) _s(s) { }
_s is constructed with its copy ctor

(But an int member, for example, has no efficiency gain.)

If none of those situations apply then it really doesn't matter. And like you said, sometimes you simply need to do more than you can do in an initializer list.
@tpd It looks like I can still initialize the _texture member in my initializer list if I arrange it appropriately in the header file, and call it last in the initializer list like so:

1
2
3
4
Text::Text(int fontSize, const char* text) : _fontPath("Assets/Fonts/8BIT.ttf"), _fontValue(text), _fontSize(fontSize), _fontColor({ 255, 255, 255, 255 }), _textTexture(loadFont(_fontPath, _fontSize, _fontValue, _fontColor))
{
	SDL_QueryTexture(_textTexture, NULL, NULL, &_textRect.w, &_textRect.h);
}


But does it actually make sense to, or should I just do it like I showed in my first example? It's my understanding that if you CAN use an initializer list, then do so, because it's more efficient (as you also pointed out)
There's nothing wrong at all with calling a function in the initialiser list (as long as that function isn't trying to do anything with the object that's in the middle of being initialised).

It's worth understanding that setting the value of a data member in the initialisation list does something different than setting the value of a data member within the body of the construstor:

- the first initialises the data member with the given value, i.e. the data member is constructed using that value to set its initial state.

- the second assigns the value to the data member after the data member has been constructed and initialised. By the time the body of the constructor is entered, the data members have already been constructed (and hence initialised), so we're assigning a new value to an already-initialised data member.

From this, it should be clear that you can set some data members using one method, and some using the other, because they are different operations.
Furthermore,
1
2
3
4
5
6
7
8
Foo::Foo( Bar x )
: foo( x ),
// foo has now been completely initialized
  bar( 2 * foo ),
// bar has now been completely initialized
  gaz( 42 )
{
}


and
1
2
3
4
5
6
Foo::Foo( Bar x )
: foo( bar ), // error: bar is uninitialized
  bar( x ),
  gaz( 42 )
{
}

Topic archived. No new replies allowed.