Какой эффект имеет следующее явное объявление оператора присвоения?

Рассмотрим следующий код:

class Object
{
  public:
    Object& operator=(const Object& object) noexcept = default;
  private:
    int i;
    // ...
};

Скажите, пожалуйста, имеет ли эффект явное объявление копирующего оператора присвоения, как не генерирующего исключения и имеющего реализацию по умолчанию?

Будет ли в автоматически сгенерированном коде проверка для защиты от присваивания в самого себя?


Ответы (3 шт):

Автор решения: KoVadim

Будет сгенерирован конструктор, который делает побитовое копирование. Защиты от присваивание самому себе нет, но она и так понятна. Очевидно, что при побитовом копировании исключение не бросается.

Имеет ли смысл слово noexcept? похоже в данном случае не имеет. Но по документации копирующий конструктор относится к "потенциально бросающим исключение" https://en.cppreference.com/w/cpp/language/noexcept_spec Но возможно, в некоторых случаях можно получить некую оптимизацию (как минимум вектор проверяет, является ли move конструктор noexcept и включает ряд оптимизаций).

А вот указание default - это хорошая идея - таким образом Вы явно декларируете, что этот конструктор Вам нужен. Что так именно и задумано.

→ Ссылка
Автор решения: AR Hovsepyan

Функции, которые являются noexcept, могут позволить компилятору выполнять некоторые оптимизации, которые в противном случае были бы недоступны.

Поскольку ваш оператор не может выбрасывать исключения, то может позволить компилятору создавать более быстрый код, не беспокоясь о сохранении стека во время выполнения.

Стандартные библиотечные контейнеры (такие как std::vector) знают о noexcept и будут использовать его для определения того, следует ли использовать семантику перемещения или семантику копирования в определенных местах.

В данном случаи, ваш оператор, присвоение выполняет по умолчанию, а значит присвоение по умолчанию всех членов не должны выбросить исключение или же весь код просто аварийно завершится вызовом std::terminate.

→ Ссылка
Автор решения: Harry

Все же отвечу, так как имеющиеся ответы мне представляются как минимум неполными...

Будет сгенерирован оператор присваивания, который выполняет присваивание каждого поля. Так что если поле не просто 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

→ Ссылка