Ernie Sanderson
Ernie Sanderson

Reputation: 434

Constructor Initializer List vs Constructor Body

Let's say someString initialization is a tad complicated, hence we write a simple member function stringInitialization() with which to initialize someString in the body of the constructor:

class DemoL {
private:

    int someNumber;
    std::string someString;

    void stringInitialization() {
        if (someNumber == 1) {
            someString = "FIRSTSTRING";
        } else if (someNumber == 2) {
            someString = "SECONDSTRING";
        } else {
            someString = "";
        }
    }

public:
    explicit DemoL(int rNumber) :
            someNumber(rNumber) {
        stringInitialization();
    }
};

This way, I'd assume, someString will be default initialized before the body of the constructor and only after that will it be modified by calling stringInitialization().

So, let's modify the code a bit, so that we initialize someString in the constructor initializer list:

class DemoL {
private:

    int someNumber;
    std::string someString;

    std::string stringInitialization() const {
        if (someNumber == 1) {
            return "FIRSTSTRING";
        } else if (someNumber == 2) {
            return "SECONDSTRING";
        } else {
            return "";
        }
    }

public:
    explicit DemoL(int rNumber) :
            someNumber(rNumber),
            someString(stringInitialization()) {}
};

Would you be so kind as to tell me whether the second variant is more efficient and correct?

Upvotes: 2

Views: 196

Answers (1)

Enlico
Enlico

Reputation: 28384

Your assumption is correct. The constructor DemoL(int rNumber) needs to be able to default construct the member someString and this is no problem because std::string is default constructible.

One obvious point is that one member could be not default-constructible, in which case you would have to initialize it.

But even if it is, default constructing it could be a waste of resources, if you are changing it right after, so the second alternative seems better to me as it goes straight to the point.

However, since stringInitialization returns by value, I would use std::move, no, this is actually a bad idea, as pointed out in the comments.

So as a conclusion:

  • the two codes are the same as regards someNumber
  • the first code default-initializes someString ("calls" std::basic_string<...>::basic_string) and then assigns it (calls std::basic_string<...>::operator=)
  • the second code constructs the return std::string value from the sting literals when the call to stringInitialization returns (calls basic_string<...>::basic_string(const char*)), and then copy-constructs someString (calls basic_string<...>::basic_string(basic_string&&)); actually copy elision happens because stringInitialization returns an rvalue.

Upvotes: 1

Related Questions