7

私は最近読んだ(そして残念ながらどこを忘れた)、operator=を書く最良の方法は次のようになっている:

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

これの代わりに:

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

考え方は、operator =が右辺値で呼び出された場合、最初のバージョンはコピーの構築を最適化できるということです。したがって、右辺値で呼び出された場合、最初のバージョンの方が高速であり、左辺値で呼び出された場合、2つは同等です。

他の人がこれについてどう思うか知りたいですか?明確性の欠如のために、人々は最初のバージョンを避けますか?最初のバージョンが良くなる可能性があり、決して悪くなることはないというのは正しいですか?

4

5 に答える 5

4

あなたはおそらくそれを以下から読んだでしょう:http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

リンクが理論的根拠をかなりよく説明していると思うので、私は多くを言うことはありません。逸話的に、最初のフォームではMSVCを使用したビルドでコピーが少なくなることを確認できます。これは、コンパイラが2番目のフォームでコピーの省略を実行できない可能性があるためです。私は、最初の形式が厳密な改善であり、2番目の形式より悪くなることは決してないことに同意します。

編集:最初の形式は少し慣用的ではないかもしれませんが、それほど明確ではないと思います。(IMO、代入演算子のコピーアンドスワップの実装を初めて見たのは驚くことではありません。)

編集#2:おっと、私はRVOではなく、コピーの省略を書くつもりでした。

于 2010-01-09T20:07:02.747 に答える
2

私は一般的に読みやすさと「驚き最小の原則」の観点から2番目のものを好みますが、パラメーターが一時的なものである場合、最初のものがより効率的である可能性があることを認めます。

最初のものは、単一のコピーだけでなく、実際にはコピーをもたらさない可能性があり、これは極端な状況では真の懸念事項である可能性があります。

例:このテストプログラムを受講してください。gcc -O3 -S(gccバージョン4.4.2 20091222(Red Hat 4.4.2-20)(GCC))は、Bのコピーコンストラクターへの呼び出しを1つ生成しますが、関数のAのコピーコンストラクターへの呼び出しは生成しません(代入演算子はとの両方にfインライン化されます)。どちらも非常に基本的な文字列クラスと見なすことができます。の割り当てとコピーは、コンストラクターで発生し、デストラクタで割り当て解除されます。ABABdata

#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");
}
于 2010-01-09T20:05:23.280 に答える
0

これを考えると

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

このようなコードで

foo bar;
bar = f();

コンパイラーがコピーコンストラクターの呼び出しを排除する方が簡単な場合があります。RVOを使用すると、での戻り値を作成otherする場所として、オペレーターのパラメーターのアドレスを使用できます。f()

この最適化は2番目のケースでも可能であるように思われますが、難しいかもしれません。(特に、オペレーターがインライン化されていない場合。)

于 2010-01-09T20:05:55.057 に答える
-2

これら2つは実際には同じです。唯一の違いは、デバッガーで「ステップイン」を押す場所です。そして、あなたはそれをどこで行うかを前もって知っておくべきです。

于 2010-01-09T19:55:59.693 に答える
-3

私はあなたが間の違いを混乱させているかもしれないと思います:

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

最初の形式は、次のことを可能にするために使用する必要があります。 (a = b) = c;

于 2010-01-09T19:46:39.780 に答える