В чем разница между делегированием конструкторов в списке инициализатора члена и в теле конструкторов

Конструкторы из C++11 позволяют нам создавать цепочки конструкторов. Например, мы можем закодировать это:

Class Foo
{
public:
    Foo()
    {
    }   

    Foo(int n): Foo()
    {
    }  
};

Я попытался делегировать Foo() как в списке инициализации члена, так и в теле кода. Я получаю одинаковые возвращаемые значения в обеих ситуациях. У меня вопрос, есть ли на самом деле какие-либо различия в обоих методах? Если они одинаковы, есть ли преимущество перед применением одного над другим?

1 ответ

[class.base.init]/6 достаточно ясно показывает, как делегировать конструкторы, и это невозможно сделать в теле конструктора.

Пример

#include <iostream>

struct A
{
    A() : a(42) {}
    A(int) : A() {}

    int a = 17;
};

struct B
{
    B() : b(42) {}
    B(int) { B(); }

    int b = 17;
};

int main()
{
    A a{0};
    B b{0};
    std::cout << a.a << " " << b.b << std::endl;
}

Идея очень проста: каждый из двух struct S выставляет конструктор, принимающий один int (это игнорируется). A делегирует его конструктору по умолчанию в списке инициализатора члена (настройка a до 42). B пытается сделать то же самое в теле конструктора.

Этот пример компилирует [godbolt] и вызывает правильные конструкторы (A(int) а также B(int)), но результат очень отличается

$ ./a.out
42 17

B конструктор по умолчанию никогда не вызывался

Почему это происходит

Какие B(int) действительно не делегирует конструктор. Вместо этого он создает новый временный объект типа B (так же, как вы могли бы сделать B b = B();) и сразу же отбрасывает его. Это не делегирует ничего в любом случае.

Единственный способ делегировать конструктор - вызвать его в списке инициализатора члена. Вы также можете делегировать только одному конструктору за раз. [Это не относится к конструкторам базовых классов, вызываемых очень похожим образом]

Другие вопросы по тегам