JohnB
JohnB

Reputation: 13713

Initialization lists and std::forward

Am I right in assuming that

class D { /* ... */ };

int f (const D & t) { return /* something calculated from t */; }

template<class T>
class C {
private:
    int m_i;
    T m_t;
    // or first m_t, then m_i -- careless order of declarations
public:
    template<class T_>
    C (T_ && t) : m_t (std::forward<T_> (t)), m_i (f (t)) {
    }
};

C<D> c (D ());

may lead to a bug since the value of t has been moved away when f(t) is called? Is there any way to avoid this problem apart from (i) using a factory function or (ii) introducing a dependency on the order in which m_i and m_t are declared?

Upvotes: 1

Views: 1211

Answers (2)

The first thing is that the order of evaluation of the initializer list is determined by the order of the members in the class definition, so in your case, it will be:

template<class T_>
C (T_ && t) 
  : m_i (f (t)), m_t (std::forward<T_> (t)) {
}

So in your case it is fine. It would also be fine if you reordered the members so that m_t is declared before m_i and you used m_t in the initialization:

T m_t;
int m_i;
template<class T_>
C (T_ && t) 
  : m_t (std::forward<T_> (t)), m_i (f (m_t))  {
}

Upvotes: 3

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153820

The member m_i is initialized first and by the time the value is clearly not moved nor will it be moved. When you initialize m_t(std::forward<T>(t)) you implicitly promise that you won't use ts value (at least, until you have given it a new one).

In general, the order of execution matters and this is true for the member initializer list, too. That is, you need to be careful in which order you declare your members when you introduce dependencies between them.

Upvotes: 2

Related Questions