Рекомендуются ли операторы копирования с идиомой копирования и обмена и проверкой самостоятельного назначения?

Здесь вы можете увидеть реализацию оператора присваивания копирования с самопроверкой проверки:

String & operator=(const String & s)
{
    if (this != &s)
    {
        String(s).swap(*this); //Copy-constructor and non-throwing swap
    }

    // Old resources are released with the destruction of the temporary above
    return *this;
}

Это хорошо для самостоятельного назначения, но плохо для производительности:

  1. как каждый раз, когда он проверяет, как будто утверждение (я не знаю, насколько оно будет оптимальным, учитывая прогноз ветвления)
  2. Также мы теряем здесь копию elision для аргументов rvalue

Так что я до сих пор не понимаю, буду ли я реализовывать std::vector"s operator= как бы я это реализовал.

2 ответа

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

String& String::operator=(String s) { // note passing by value!

    std::swap(s, *this); // expected to juggle couple of pointers, will do nothing for self-assingment
    return *this;
}

Также обратите внимание, что выгоднее принимать аргумент по значению.

как каждый раз, когда он проверяет, как будто утверждение (я не знаю, насколько оно будет оптимальным, учитывая прогноз ветвления)

Я думаю, что вы попали в круг преждевременной оптимизации здесь.

Проверка на самостоятельное назначение -> самостоятельное назначение не требуется, если вы правильно написали код -> почему бы не написать swap явно если ты это имеешь ввиду? -> мы вернулись на круги своя

Реально я бы просто внедрил Allocator и не беспокоился об этом.

Также мы теряем здесь копию elision для аргументов rvalue

Я так не думаю.

#include <iostream>

#define loud(x) std::cout << x << "\n";

struct foo
{
    foo() { loud("default") }
    ~foo() { loud("destruct") }

    foo(const foo&) { loud("copy") }
    foo(foo&&) { loud("move") }

    foo & operator=(const foo & s)
    {
        if (this != &s)
        {
            loud("copy assign")
        }

        return *this;
    }
};

int main()
{
    foo f;
    foo g;
    g = f;
}

Выходы:

default
default
copy assign
destruct
destruct

Это с -fno-elide-constructors,


Вы утверждаете, что ветка может быть проблемой, но вывод сборки для -O2 показывает, что GCC даже не испускает код для operator= и просто выводит "copy assign" строка напрямую. Да, я понял, что у меня есть упрощенный пример, но это действительно неправильный конец стопки.

Другие вопросы по тегам