Search code examples
c++c++11language-lawyerinitializer-listmember-initialization

Member initializer list. Order of arguments evaluation


Example of a code with a member initializer list.

#include <memory>

struct Throwable
{
    Throwable()
    {
        throw "Exception!";
    }
};

struct A
{
    A() : t(Throwable()), i(new int()) {}

    Throwable t;
    std::unique_ptr<int> i;
};

Can I have got a memory leak if there could be the following evaluation order?

  1. new int()
  2. Throwable()
  3. t()
  4. i()

What is the order in the Standard? We have some rules.

https://en.cppreference.com/w/cpp/language/initializer_list

3) Then, non-static data members are initialized in order of declaration in the class definition.

So t will be constructed before i.

https://en.cppreference.com/w/cpp/language/eval_order

9) Every value computation and side effect of the first (left) argument of the built-in comma operator , is sequenced before every value computation and side effect of the second (right) argument.

But member initializer list does not use all comma rules because of the previous reference. And it is not the comma operator (https://en.cppreference.com/w/cpp/language/operator_other#Built-in_comma_operator).

10) In list-initialization, every value computation and side effect of a given initializer clause is sequenced before every value computation and side effect associated with any initializer clause that follows it in the brace-enclosed comma-separated list of initalizers.

And https://en.cppreference.com/w/cpp/language/list_initialization

List initialization is performed in the following situations:

5) in a member initializer list of a constructor if braced-init-list is used

I have another case.

Could you provide the rule which defines the order of arguments evaluation in a member initializer list?


Solution

  • No, this evaluation order that would potentially cause you to leak is guaranteed not to happen. The expression within each mem-initializer is a full-expression ([intro.execution] §5.3). And [intro.execution] §9 tells us

    Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

    So in other words, the evaluation of each expression used to initialize a member is completed before evaluation of the expression for the next member starts.