Использование noexcept
Для чего используется noexcept в конструкторе перемещения? Насколько я понял, он используется, чтобы вызывать не конструктор перемещения, а копирующий конструктор. Верный ли мои рассуждения?
class String
{
size_t len;
char* buffer;
public:
String(const char* str)
{
len = strlen(str);
buffer = new char[len + 1];
memcpy(buffer, str, len + 1);
std::cout << "Call CTR " << str << endl;
}
friend std::ostream& operator<< (std::ostream& stream, const String& str);
~String()
{
delete[] buffer;
}
String& operator= (const String& str)
{
delete[] buffer;
if (this == &str)
{
}
this->len = str.len;
buffer = new char[len + 1];
memcpy(buffer, str.buffer, len + 1);
return *this;
std::cout << "Call COPY " << str << endl;
}
char& operator[] (unsigned int index)
{
return buffer[index];
}
String(const String& str)
:
len(str.len)
{
buffer = new char[len + 1];
memcpy(buffer, str.buffer, len + 1);
}
String(const String&& str) noexcept
{
std::cout << "MOVE СTR\n" << str << endl;
}
};
std::ostream& operator<< (std::ostream& stream, const String& str)
{
stream << str.buffer;
return stream;
}
int main(int argc, char* argv[])
{
String str = "string";
String str2 (std::move(str));
return 0;
}
Но если использовать либо нет noexcept все равно вызывается этот конструктор.
Ответы (1 шт):
Если move-ctor вашего класса не помечен как noexcept, действительно вместо него будет вызываться конструктор копирования, но в одном достаточно узком случае.
Допустим у вас есть вектор, в который вы добавляете объекты вашего класса. В какой-то момент вместимости вектора (размера выделенной под него памяти) перестает хватать и вектор делает переаллокацию - выделяет новую память с запасом и переносит туда содержимое старого фрагмента памяти. И если у вас кидающий перемещающий конструктор, вместо него вектор вызовет конструктор копирования.
Это сделано для того, чтобы сохранить состояние вектора в случае вылета исключения - если мы копировали объекты, можно просто почистить новую память и старое состояние вектора останется валидным, а в случае перемещения, непонятно, что куда возвращать.
Другие контейнеры стандартной библиотеки следуют тому же правилу
upd
Добавлю что наличие noexcept у методов позволяет компилятору лучше оптимизировать исполняемый файл (хотя к конструкторам копирования/перемещения это отношения не имеет).
Также cpp core guidelines рекомендуют всегда помечать move-ctor noexcept так как кидающий перемещающий конструктор "нарушает ожидания большинства людей": http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-move-noexcept