Как использовать noexcept в операторе присваивания с идиомой копирования и свопинга?
Оператор присваивания переходов часто должен быть объявлен noexcept (т.е. хранить тип в контейнерах STL). Но идиома "копирование и своп" позволяет определять как операторы присваивания копий, так и операции перемещения в одном фрагменте кода. Что делать с noexcept спецификатором в этом случае? Конструкция копии может быть брошена, но я сомневаюсь, может ли она нарушить спецификатор noexcept.
// Is it correct considering that T copy constructor can throw?
T& operator=(T other) noexcept;
Ответы
Ответ 1
Поскольку копия сделана со стороны вызывающего абонента, она не является частью вашей функции. Поэтому он не может контролироваться вашей функцией и, следовательно, вы не можете включать эту информацию в спецификацию noexcept
.
Единственное, что вы можете сделать, это безопасное воспроизведение и добавление обоих параметров в вашу спецификацию noexcept
. Конечно, это означает, что вы получаете некоторые ложные отрицания.
Ответ 2
Как обычно, Даниэль Фрей правильный. Все, что мне нужно, это показать фрагмент кода, который иллюстрирует точку.
#include <iostream>
struct foo {
foo() = default;
foo(const foo&) {
std::cout << "throw\n";
throw 1;
}
foo& operator =(foo) noexcept {
return *this;
}
};
int main() {
foo f, g;
try {
f = g; // throws
}
catch(int) {
std::cout << "catch\n";
}
}
При компиляции с gcc 4.8.1 (-std=c++11 -Wall -Wextra -pedantic
) он не дает никаких предупреждений. Запуск кода выводит следующий результат:
throw
catch
Поэтому конструктор копирования бросает при вызове, но не рассматривается внутри operator =()
, и поэтому обещание noexcept
выполнено. В противном случае завершение будет вызвано до того, как catch
может быть распечатано.