явный конструктор копии или неявный параметр значением

Я недавно читал (и к сожалению забыл, где), что лучший способ записать оператор = похож на это:

foo &operator=(foo other)
{
    swap(*this, other);
    return *this;
}

вместо этого:

foo &operator=(const foo &other)
{
    foo copy(other);
    swap(*this, copy);
    return *this;
}

Идея состоит в том, что, если оператор = называют с rvalue, первая версия может оптимизировать далеко конструкцию копии. Таким образом, при вызове с rvalue первая версия быстрее и при вызове с lvalue эти два эквивалентны.

Мне любопытно относительно того, что другие люди думают об этом? Люди избежали бы первой версии из-за отсутствия явности? Я корректен, что первая версия может быть лучше и никогда не может быть хуже?

6
задан Jon Seigel 10 April 2010 в 18:28
поделиться

5 ответов

Вы, наверное, читали это по: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

Мне нечего сказать, так как мне кажется, что ссылка довольно хорошо объясняет логическое обоснование. Анекдотически я могу подтвердить, что первая форма приводит к меньшему количеству копий в моих сборках с MSVC, что имеет смысл, так как компиляторы могут быть не в состоянии сделать копирование на второй форме. Я согласен, что первая форма - это строгое улучшение и никогда не бывает хуже второй.

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

Edit #2: Oops, я имел в виду написание разрешения на копирование, а не RVO.

4
ответ дан 17 December 2019 в 22:13
поделиться

Учитывая это

foo &foo::operator=(foo other) {/*...*/ return *this;}
foo f();

в подобном коде

foo bar;
bar = f();

компилятору, возможно, будет проще устранить вызов конструктора копирования. С помощью RVO он мог бы использовать адрес параметра оператора other в качестве места для f(), чтобы построить его возвращаемое значение по этому адресу.

Кажется, что такая оптимизация возможна и для второго случая, хотя, на мой взгляд, это может быть сложнее. (Особенно, когда оператор не является инсценированным.)

.
0
ответ дан 17 December 2019 в 22:13
поделиться

Эти двое на самом деле одни и те же. Единственная разница заключается в том, где вы нажимаете "Step In" в отладчике. И вы должны заранее знать, где это сделать.

-2
ответ дан 17 December 2019 в 22:13
поделиться

Я думаю, что вы можете перепутать разницу между:

foo &operator=(const foo &other); и
const foo &operator=(const foo &other);

Первая форма должна быть использована, чтобы разрешить: (a = b) = c;

-3
ответ дан 17 December 2019 в 22:13
поделиться

Я, как правило, предпочитаю вторую из читаемости и «наименьшую точку зрения« минимум неожиданности », однако я признаю, что первый может быть более эффективным, когда параметр является временным.

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

E.G. Возьмите эту тестовую программу. GCC -O3 -S (GCC версия 4.4.2 20091222 (RED HAT 4.4.2-20) (GCC)) генерирует один вызов COPTOR COPTOR BOPE, но нет вызовов к конструктору копирования копии для функции f (оператор назначения активирован как для обоих A и B ). А и B можно принимать, чтобы быть очень основными классами строки. Распределение и копирование для данных будут происходить в конструкторах и дефинции в деструкторе.

#include <algorithm>

class A
{
public:
    explicit A(const char*);
    A& operator=(A val)      { swap(val); return *this; }
    void swap(A& other)      { std::swap(data, other.data); }
    A(const A&);
    ~A();

private:
    const char* data;
};

class B
{
public:
    explicit B(const char*);
    B& operator=(const B& val)  { B tmp(val); swap(tmp); return *this; }
    void swap(B& other)         { std::swap(data, other.data); }
    B(const B&);
    ~B();

private:
    const char* data;
};

void f(A& a, B& b)
{
    a = A("Hello");
    b = B("World");
}
2
ответ дан 17 December 2019 в 22:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: