Каковы правила для noexcept для стандартных конструкторов перемещения по умолчанию?

В особенности в связи с std::vector важно, чтобы типы были noexcept возможными.

Итак, при объявлении конструктора перемещения = default, как в

struct Object1
{
    Object1(Object1 &&other) = default;
};

std::is_nothrow_move_constructible<Object1>::value будет true, так как каждый член (0 здесь) Object1 конструктив невозможен, на который отвечает здесь.

Но что произойдет, если конструктор перемещения перемещения объявлен, а затем = default, определенный как в следующем коде?

struct Object2
{
    Object2(Object2 &&other);
};
Object2::Object2(Object2 &&other) = default;

С g++ 4.9.2 std::is_nothrow_move_constructible<Object2>::value есть false, и я должен отметить как объявление, так и определение как noexcept, чтобы сделать его true.

Теперь меня интересует, каковы фактические правила. Тем более, что пункт 22 в Эффективный современный С++ (Скотт Майерс), кажется, дает плохой совет, предлагая реализовать конструктор перемещения pimpl-idiom, как я это делал с Object2.

Ответ 1

[dcl.fct.def.default]/р2

Если в первом объявлении функция явно дефолтована,

  • он неявно считается constexpr, если подразумевается декларация, и
  • он имеет такую ​​же спецификацию исключения, как если бы он был неявно объявлен (15.4).

Эти правила не применяются, если функция явно дефолтована в более позднем объявлении, как в следующем примере, поэтому вместо деструкторов функция считается noexcept(false) по умолчанию, как и большинство других функций.

Так как явное дефолт может быть в другой единицы перевода - и в случае pimpl находится в другом TU - нет никакого общего способа для компилятора выяснить после просмотра определения класса только, будет ли конструктор перемещения бросать, если функция явно не определена по умолчанию в определении класса (т.е. при первом объявлении).