Есть ли какая-то особая причина, почему конструктор перемещения не показан в приведенном ниже фрагменте?

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) может быть опущена путем создания автоматического объекта непосредственно в объект исключения

Кажется, что ни один из компиляторов не использует эту оптимизацию. Одна из причин может заключаться в том, что это просто не стоит делать, поскольку усилия лучше потрачены на другие оптимизации. Я не думаю, что в стандарте есть что-то, запрещающее эту оптимизацию.