Поскольку операция перемещения выполняется при "захвате" ресурсов, она обычно не резервирует ресурсы. В результате операции перемещения обычно не передают исключений. Когда создается функция перемещения, неспособная передавать исключения, об этом факте следует сообщить библиотеке. Как будет описано вскоре, если библиотека не знает, что конструктор перемещения не будет передавать исключений, она предпримет дополнительные меры по отработке возможности передачи исключения при перемещении объекта этого класса.
noexcept в конструкторе. Введенный новым стандартом оператор noexcept подробно рассматривается в разделе 18.1.4, а пока достаточно знать, что он позволяет уведомить, что функция не будет передавать исключений. Оператор noexcept указывают после списка параметров функции. В конструкторе его располагают между списком параметров и символом :, начинающим список инициализации конструктора:
class StrVec {
public:
StrVec(StrVec&&) noexcept; //
//
};
StrVec::StrVec(StrVec &&s) noexcept : /*
{ /*
Оператор noexcept следует объявить и в заголовке класса, и в определении, если оно расположено вне класса.
noexcept.
Понимание того, почему необходим оператор noexcept, может помочь углубить понимание того, как библиотека взаимодействует с объектами написанных вами типов. В основе требования указывать, что функция перемещения не будет передавать исключения, лежат два взаимосвязанных факта: во- первых, хотя функции перемещения обычно не передают исключений, им это разрешено. Во-вторых, библиотечные контейнеры предоставляют гарантии относительно того, что они будут делать в случае исключения. Например, класс vector гарантирует, что, если исключение произойдет при вызове функции push_back(), сам вектор останется неизменным.
Теперь рассмотрим происходящее в функции push_back(). Подобно соответствующей функции класса StrVec (см. раздел 13.5), функция push_back() класса vector могла бы потребовать пересоздания вектора. При пересоздании вектор перемещает элементы из прежней своей области памяти в новую, как в функции reallocate() (см. раздел 13.5).
Как только что упоминалось, перемещение объекта обычно изменяет состояние оригинального объекта. Если пересоздание использует конструктор перемещения и этот конструктор передает исключение после перемещения некоторых, но не всех элементов, возникает проблема. Перемещенные элементов в прежнем пространстве были бы изменены, а незаполненные элементы в новом пространстве еще не будут созданы. В данном случае класс vector не удовлетворял бы требованию оставаться неизменным при исключении.
С другой стороны, если класс vector использует конструктор копий, то при исключении он может легко удовлетворить это требование. В данном случае, пока элементы создаются в новой памяти, прежние элементы остаются неизменными. Если происходит исключение, вектор может освободить зарезервированное пространство (оно могло бы и не быть успешно зарезервировано) и прекратить операцию. Элементы оригинального вектора все еще существуют.
Во избежание этой проблемы класс vector должен использовать во время пересоздания конструктор копий вместо конструктора перемещения, noexcept.
Оператор присваивания при перемещении делает то же, что и деструктор с конструктором перемещения. Подобно конструктору перемещения, если оператор присваивания при перемещении не будет передавать исключений, то его следует объявить как noexcept. Подобно оператору присвоения копии, оператор присваивания при перемещении должен принять меры против присвоения себя себе:
StrVec &StrVec::operator=(StrVec &&rhs) noexcept {
//
if (this != &rhs) {
free(); //
elements = rhs.elements; //
first_free = rhs.first_free;