Adam Rosen
Adam Rosen

Reputation: 133

I'm confused about this C++ constructor

I tried searching for an answer, but not sure exactly the best terms to use to describe this...

I am reading a book on SFML programming, and one of the examples has me confused with the usage of the constructor.

Lets say we have class A and class B. Class A has a member variable of type B (memberB). The constructor for A looks like:

A::A() : OtherMemberType(with, params), memberB()
{...}

Given that memberB is being initialized with the default constructor in the initialization list, what is the purpose of explicitly listing it in the list? Wouldn't the same effect be had without including it in the list?

Thanks

EDIT: Thanks for the answers. I have now learned the (basic) difference of value-initialization vs. default-initialization.

For more context, since the idea of "class B may be broken was brought up", here is the code example from the text SFML Game Development:

class Game
{
    public:Game();
        void             run();

    private:
        void             processEvents();
        void             update();
        void             render();

    private:
        sf::RenderWindow mWindow;
        sf::CircleShape  mPlayer;
};

Game::Game()
: mWindow(sf::VideoMode(640, 480), "SFML Application")
, mPlayer()
{
    mPlayer.setRadius(40.f);
    mPlayer.setPosition(100.f, 100.f);
    mPlayer.setFillColor(sf::Color::Cyan);
}

So with that context, does anyone know some of the specifics of SFML? Is sf::CircleShape "broken", or is this a redundant call to the default constructor?

Adam

Upvotes: 13

Views: 1408

Answers (3)

Given what mike and juan have said, I'd say that class B's implementation is broken iff it requires to be value-initialized like that unless it'd be reasonably expected to behave that way.

Generally, given a properly designed class - with a user-provided default constructor iff if has POD members - there should be no difference in behavior between value- and default-initializing the member of type B.

Some special classes may not perform zero-initialization of their members and they may lack a default constructor. std::array is one such class. They attempt to retain the performance of the raw type underlying their implementation. Members of such classes will require the value initialization.

There are several possibilities:

  1. Class B is has the usual behavior the value initialization is superfluous. Specifically:

    a) class B has no POD-typed members, and the non-POD typed member types are all implemented in line with possibility #1, or

    b) class B's user-written default constructor initializes all POD-typed members as appropriate.

  2. Class B has the semantics of a performance-optimized type, such as a numerical type or a replacement for raw C arrays. It lacks a default constructor and won't initialize unless you perform value initialization. Example: std::array<T> where T is POD.

  3. Class B is a template parameter. In absence of any constraints on B, the value initialization is the only safe choice. B could be std::array, after all.

  4. Class B is broken. Its members will be properly initialized if its instances are value-initialized. It needs to be fixed.

Upvotes: 2

Mike Seymour
Mike Seymour

Reputation: 254741

By including it in the initialiser list, the member is value-initialised. If it weren't, it would be default-initialised. Whether there's a difference depends on the type.

If it's a class type with a declared default constructor, then there's no difference: that constructor will be used in either case.

Otherwise, value-initialisation will zero-initialise primitive types (and primitive members of class types), while in some circumstances default-initialisation will leave them uninitialised, with an indeterminate value.

UPDATE: In your specific case, the class does have a default constructor, so the explicit initialisation is redundant. But redundancy isn't necessarily a bad thing - it indicates that it's being deliberately value-initialised, not just forgotten about.

Upvotes: 14

juanchopanza
juanchopanza

Reputation: 227578

Initializing the member in the initializer list value-initializes it. Omitting it from the list default-initializes it,

If B is a non-aggregate and has a default constructor, there is no difference.

If B is an aggregate, then there may be a difference. default-initializing it means if it contains built-ins these may not get initialized. value-initializing it would eventually have the effect of zero-initializing its members.

This is an example where the semantics of the initialization would be different:

struct B
{
  int i, j, k;
};

struct A
{
  A() : b() {} // value-initializes b: b.i, b.j, b.k zero initialized

  B b;
};

struct AA
{
  AA() {} // default-initializes b: b.i, b.j, b.k have no initialization

  B b;
};

Upvotes: 16

Related Questions