1

コピーの省略のため、内部コピーが保持される限り、通常はオブジェクトを値で渡すことが推奨されます。次の状況はどうでしょうか。

struct A
{
    A(int x, int y) : x(x), y(y) {}
    int x, y;
};

struct B
{
    B(A a) : a(a) {}                // 1
    B(const A& a) : a(a) {}         // 2
    A a;
};

struct C : A
{
    C(A a) : A(a) {}                // 3
    C(const A& a) : A(a) {}         // 4
};

struct D : B, C
{
    D(A a) : B(a), C(a) {}          // 5
    D(const A& a) : B(a), C(a) {}   // 6
};

連鎖コピーは引き続き省略されますか、つまり、1、3、および 5 が望ましいですか? それとも2、4、6?インライン化に依存しますか?

4

1 に答える 1

2

あなたの例では、大きな違いはないと思います。のコンストラクターにAは副作用がないため、コピー省略に関する標準の規則は関係ありません。重要なのは、オプティマイザーが実際に達成できることだけです。コンストラクターがインライン化されると、どちらの場合もほぼ同じになると思います。このコンストラクターをインライン化できない特別な理由はありません (小さく、クラス定義で定義されています)。

Bコンストラクターをインライン化できない場合、またはAコンストラクターに副作用がある場合は、データ メンバーへのコピーが発生する必要があります (Cおよびの基本クラス サブオブジェクトについても同じですD)。コピーの省略に関する標準の規則では、パラメーターからデータ メンバーへのコピーを省略することは許可されていないため、実際には必要のないコピーが表示される状況です。

Aにコピーよりも効率的なムーブ コンストラクターがあると仮定すると、呼び出し元が一時オブジェクトを渡す場合、次の例は明らかに有利です。

struct B
{
    B(A a) : a(std::move(a)) {}
    A a;
};

その理由は、一時的なものを直接関数の引数に構築し、それをデータ メンバーに移動できるからです。2/4/6 は、(安全に) 左辺値参照から const へのデータ メンバーに移動できません。1/3/5 は、パラメーターaが再び使用されないため安全に移動できますが、(a) で許可を与えるstd::moveか、(b) 以下で同等でない限り、コンパイラーはそれ自体でその変更を行うことはできません。 「あたかも」のルール。

呼び出し元が左辺値を渡す場合、コンストラクターはコピーしてから移動するため、コンストラクターは (2) よりわずかに遅くなる可能性がありますが、(2) はコピーするだけです。このコストを無視することもできます (移動は非常に安価であると想定されているため) か、別const A&の andA&&コンストラクターを記述することができます。一般的な経験則は前者を行うことだと思います。

于 2012-11-08T10:33:07.810 に答える