Почему инициализация копирования с использованием конструкции скобок elide для копирования / перемещения в C ++ 14 с отключенным разрешением копирования? - PullRequest
4 голосов
/ 20 апреля 2020

Вот программа на C ++ для сравнения прямой инициализации (без =) с копией инициализации (=) : *

#include <iostream>


struct A {
    A(int) { std::cout << "A(int)" << std::endl; }
    A(A&) { std::cout << "A(A&)" << std::endl; }
    A(A&&) { std::cout << "A(A&&)" << std::endl; }
};


int main() {
    A a(1);     // direct initialisation
    A b{1};     // direct initialisation
    A c = 1;    // copy initialisation
    A d = (1);  // copy initialisation
    A e = {1};  // copy initialisation
}

Компиляция программы на C ++ 14 с copy elision отключена и запуск ее с помощью следующей команды:

$ clang++ -std=c++14 -fno-elide-constructors main.cpp && ./a.out

производит следующий вывод:

A(int)
A(int)
A(int)
A(A&&)
A(int)
A(A&&)
A(int)

Почему инициализация копирования с фигурными скобками (e) исключает конструкцию копирования / перемещения?


* Мотивация этого сравнения состояла в том, чтобы понять, как оператор возврата функции (return expression) работает с C ++ 11. При возврате по значению можно использовать прямую инициализацию или копировать инициализацию возвращаемого значения функции. Последнее более сложно, чем инициализация копирования переменной, как здесь, потому что инициализация возвращаемого функцией значения из объекта, обозначенного expression, включает попытку вызова конструктора перемещения типа, возвращающего функцию, сначала (даже если expression является lvalue), прежде чем вернуться к его конструктору копирования. А начиная с C ++ 17, эта конструкция копирования / перемещения гарантированно будет исключена, если expression является предварительным значением (обязательно оптимизация возвращаемого значения ), в то время как оно может быть исключено, если expression является glvalue (необязательно оптимизация именованного возвращаемого значения ).

1 Ответ

6 голосов
/ 20 апреля 2020

копировать инициализацию с фигурными скобками

Такой вещи нет. Если вы используете инициализированный объект с помощью braced-init-list, вы выполняете некоторую форму инициализации списка . Существует две формы этого: инициализация копирования списка и инициализация прямого списка. В C ++ 14 они не имеют отношения к инициализации копирования и прямой инициализации (технически прямая инициализация списка - это грамматическая форма прямой инициализации , но, поскольку обходы инициализации списка все, что прямая инициализация сделала бы , проще сказать, что прямая инициализация списка - это его собственный зверь).

Инициализация списка как концепция инициализирует объект. Использование Typename t{} - это прямая инициализация списка, а Typename t = {} - инициализация копирования списка. Но независимо от того, какая форма задействована, временное создание не создается ; Инициализация списка инициализирует рассматриваемый объект. Единственный объект в вашем примере это e, то есть это объект, который инициализируется.

В соответствии с C ++ 14 правилами для инициализации списка , e получает инициализируется , вызывая конструктор , передавая ему значение 1, которое является единственным значением в списке фигурных скобок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...