Какой эффект имеет следующее явное объявление оператора присвоения?
Рассмотрим следующий код:
class Object
{
public:
Object& operator=(const Object& object) noexcept = default;
private:
int i;
// ...
};
Скажите, пожалуйста, имеет ли эффект явное объявление копирующего оператора присвоения, как не генерирующего исключения и имеющего реализацию по умолчанию?
Будет ли в автоматически сгенерированном коде проверка для защиты от присваивания в самого себя?
Ответы (3 шт):
Будет сгенерирован конструктор, который делает побитовое копирование. Защиты от присваивание самому себе нет, но она и так понятна. Очевидно, что при побитовом копировании исключение не бросается.
Имеет ли смысл слово noexcept? похоже в данном случае не имеет. Но по документации копирующий конструктор относится к "потенциально бросающим исключение" https://en.cppreference.com/w/cpp/language/noexcept_spec Но возможно, в некоторых случаях можно получить некую оптимизацию (как минимум вектор проверяет, является ли move конструктор noexcept и включает ряд оптимизаций).
А вот указание default - это хорошая идея - таким образом Вы явно декларируете, что этот конструктор Вам нужен. Что так именно и задумано.
Функции, которые являются noexcept, могут позволить компилятору выполнять некоторые оптимизации, которые в противном случае были бы недоступны.
Поскольку ваш оператор не может выбрасывать исключения, то может позволить компилятору создавать более быстрый код, не беспокоясь о сохранении стека во время выполнения.
Стандартные библиотечные контейнеры (такие как std::vector) знают о noexcept и будут использовать его для определения того, следует ли использовать семантику перемещения или семантику копирования в определенных местах.
В данном случаи, ваш оператор, присвоение выполняет по умолчанию, а значит присвоение по умолчанию всех членов не должны выбросить исключение или же весь код просто аварийно завершится вызовом std::terminate.
Все же отвечу, так как имеющиеся ответы мне представляются как минимум неполными...
Будет сгенерирован оператор присваивания, который выполняет присваивание каждого поля. Так что если поле не просто int, а что-то посложнее - будет вызван соответствующий оператор присваивания для этого типа.
Проверки на присваивание самому себе не будет.
noexcept не соответствует сигнатуре оператора присваивания по умолчанию, так что GCC, например, с ним просто не скомпилирует. VC++ скомпилирует без вопросов, но в таком случае при генерации исключения "с им, как с предателем" (с) - вызов terminate() без возможности перехвата сгенерированного исключения.
Вот код для VC++, демонстрирующий сказанное -
struct Test
{
Test& operator = (const Test& t) { cout << "Test =\n"; throw runtime_error("..."); return *this; }
};
class Object
{
public:
Object& operator=(const Object& object) noexcept = default;
private:
int i;
Test t;
};
void term()
{
cout << "Terminate\n";
}
int main(int argc, char * argv[])
{
set_terminate(term);
Object a, b;
try {
a = b;
a = a;
} catch(exception&e)
{
cout << "Exception\n";
}
}
Для GCC, как я уже говорил, компиляции с noexcept не будет, а без него - см. https://ideone.com/Xj8LUS