Есть ли какая-то особая причина, почему конструктор перемещения не показан в приведенном ниже фрагменте?
gcc, clang и VS2015 не возвращают вызов конструктору перемещения в коде ниже, после бросания объекта a
. Мне кажется, что выполнены условия, установленные в пулевой точке (31.2) §8.12 [class.copy]/31 (N4140).
#include <iostream>
struct A
{
A() { std::cout << "Default ctor " << '\n'; }
A(const A& a) { std::cout << "Copy ctor" << '\n'; }
A(A&& a) { std::cout << "Move ctor" << '\n'; }
~A() { std::cout << "Destructor " << '\n'; }
};
int main()
{
try
{
A a;
throw a;
}
catch(A& a) { std::cout << "Caught" << '\n'; }
}
Обратите внимание, что a
является значением l, но, согласно § 12.8/32, разрешение перегрузки
для выбора конструктора для копии сначала выполняется так, как если бы объект был обозначен rvalue. То есть вызов конструктора перемещения в порядке. Если вы удалите определение конструктора перемещения выше, вызывается конструктор копирования, но опять же, он не удаляется!
Я понимаю, что в "Стандарте" не указан мандат на копирование, но мне любопытно узнать, есть ли какое-то особое условие, которое могло бы оправдать тот факт, что упомянутые выше три компилятора избегают этой оптимизации в этом конкретном примере.
Пример вывода для gcc из приведенной выше ссылки:
g++ -std = С++ 14 -O2 -Wall -pedantic -pthread main.cpp && & &./a.out
По умолчанию ctor
Переместить ctor
Деструктор
Пойманный
Деструктор
Ответы
Ответ 1
Согласно 12.8 [class.copy], пункт 31, вторая пуля копия локальной переменной, которая бросается, может быть удалена:
в выражении throw, когда операндом является имя энергонезависимого автоматического объекта (кроме параметра функции или catch-clause), объем которого не выходит за пределы самого внутреннего (если таковой имеется), операция копирования/перемещения из операнда в объект исключения (15.1) может быть опущена путем создания автоматического объекта непосредственно в объект исключения
Кажется, что ни один из компиляторов не использует эту оптимизацию. Одна из причин может заключаться в том, что это просто не стоит делать, поскольку усилия лучше потрачены на другие оптимизации. Я не думаю, что в стандарте есть что-то, запрещающее эту оптимизацию.