Подтвердить что ты не робот

Инициализаторы элементов нестатического ввода С++, немного запутанные

Я немного смущен, почему следующий код делает то, что он делает:

class Base
{
public:
    Base() = default;
    Base(const Base &) =delete;
    Base &operator=(const Base &) = delete;
    Base(const char*) {}
};

class Holder
{
public:
    Holder() = default;
private:
    // Base b = Base();
    Base b2 = {};
};

int main()
{
    Holder h;
}

в этом воплощении, он компилируется, однако, если я не комментирую Base b = Base();, он дает следующую ошибку:

main.cpp:15:17: error: use of deleted function 'Base::Base(const Base&)'
   Base b = Base();
                 ^
main.cpp:5:6: note: declared here
      Base(const Base &) =delete;
      ^

и я просто не могу найти в стандарте, почему он пытается вызвать конструктор копирования для инициализатора Base b = Base(), и почему он не вызывает Base b2 = {}... или это только один из тех немного неясности, которая скрыта в нескольких словах в абзаце где-то?

Можете ли вы дать (краткое) объяснение, почему это происходит?

(coliru: http://coliru.stacked-crooked.com/a/c02ba0293eab2ce5)

4b9b3361

Ответ 1

Это потому, что концептуально эта строка построена из Base(), для которой требуется конструктор copy/move. Вероятная причина, по которой вы не знали об этом, заключается в том, что это выражение обычно вызывает копирование elision: стандартная оптимизация. Это один из тех, что были С++.

(31.3) - когда объект временного класса, который не был связан с ссылка (12.2) будет скопирована/перенесена в объект класса с тем же cv-unqualified тип, операция копирования/перемещения может быть опущена построение временного объекта непосредственно в цель пропущено копирование/перемещение.

Как работает Base b2 = {}, см.

(3.4) - В противном случае, если в списке инициализаторов нет элементов, а T - тип класса с конструктором по умолчанию, объект значение инициализации.

Вы можете просто сделать Base b;.

Ответ 2

T object = {arg1, arg2, ...}; является синтаксисом для инициализации списка. Нет никакого копирования.

T object = T() не является инициализацией списка. Правый операнд создает временную инициализацию значения, а object инициализируется движением или копией. Перемещение и копирование могут быть отменены, но тип должен быть подвижным или скопированным, иначе это не разрешено.