Почему член инициализатора вызывает дополнительный вызов конструктора при перемещении? - PullRequest
0 голосов
/ 17 апреля 2019

Когда инициализатор члена используется в классе, у которого есть конструктор перемещения, конструктор инициализированного члена вызывается при перемещении окружающего класса. Почему это происходит? Пожалуйста, предоставьте ссылки на стандарт. У меня есть предположение относительно того, что происходит, с примерами, приведенными ниже.

Кроме того, в немного другом сценарии, почему конструктор элемента не вызывается, если инициализированный элемент имеет тип данных old-old-data?

Кроме того, каковы лучшие практики в отношении инициализаторов элементов и конструкторов перемещения?

#include <bits/stdc++.h>

using namespace std;
struct C {
    void do_stuff(){cout<<"stuff";}
    C(){cout<<"C ctor"<<endl;}
    ~C(){cout<<"C DTOR"<<endl;}
};
struct Foo {

ifdef MEMBER_INIT
    Foo() {cout<<"Foo ctor"<<endl;};
#else
    Foo() : ptr(new C) {cout<<"Foo ctor"<<endl;};
#endif

    Foo(Foo &) = delete;
    Foo & operator=(Foo &) = delete;
    Foo & operator=(Foo &&) = delete;
    Foo(Foo && rhs){cout<<"Foo MOVE ctor"<<endl; rhs.ptr.swap(this->ptr); }
    ~Foo(){cout << "Foo DTOR "; if(ptr) ptr->do_stuff(); cout<<endl; }

#ifdef MEMBER_INIT
    unique_ptr<C> ptr = make_unique<C>();
#else
    unique_ptr<C> ptr;
#endif

};

int main()
{
    Foo f;
    Foo f2(move(f));
}

РЕЗУЛЬТАТЫ:

g++ -std=c++14 x.cc && ./a.out
    C ctor
    Foo ctor
    Foo MOVE ctor
    Foo DTOR stuff
    C DTOR
    Foo DTOR

g++ -DMEMBER_INIT -std=c++14 x.cc && ./a.out
    C ctor
    Foo ctor
    C ctor
    Foo MOVE ctor
    Foo DTOR stuff
    C DTOR
    Foo DTOR stuff
    C DTOR

Почему использование инициализатора члена вызывает другой вызов конструктора для C? Почему при использовании инициализатора члена деструктор Foo запускает C-> do_stuff ()?

Моя задача состоит в том, чтобы инициализаторы членов оценивались для ВСЕХ типов конструктора до запуска фактического конструктора (в данном случае конструктора перемещения). Это правильно?

Я бы хотел, чтобы в стандарте были ссылки, которые подтверждают или противоречат моему предположению.

1 Ответ

0 голосов
/ 17 апреля 2019

Когда определено MEMBER_INIT, конструктор перемещения выполняет ptr инициализацию с использованием инициализатора в классе и становится

Foo(Foo && rhs): ptr{make_unique<C>()}

В противном случае он инициализируется по умолчанию.

15.6.2 Инициализация баз и членов [class.base.init]
9 В не делегирующем конструкторе, если данный потенциально сконструированный подобъект не обозначен с помощью mem-initializer-id (включая случай, когданет mem-initializer-list, потому что конструктор не имеет ctor-initializer), тогда

объект инициализируется из своего инициализатора члена по умолчанию, как указано в 11.6;

Обычно вы забыли инициализировать поле ptr вручную, переместив:

Foo(Foo && rhs): ptr{::std::move(rhs.ptr)}
...