3

オブジェクト a の独自のコピーに対して、freeFunct に const 以外の処理を実行させたいと考えています。

実際のコードケースでは、多くの異なるパラメーターを取り、それらすべてからいくつかのパブリック関数を呼び出し、それを任意のクラスの非静的メンバー関数にする意味がないため、freeFunct はフリー関数である必要があるとしましょう。

それを宣言する3つの異なる方法が頭に浮かびます。

3番目の解決策の方が悪いと感じています。

最初の2つに違いはありますか?

もっと良いものはありますか?

void freeFunct1(A a){
    a.doStuff(); 
}

void freeFunct2(const A& a){
    A b = a; 
    b.doStuff(); 
}

/**users of freeFunct3 are expected 
 *to give a copy of their variable: 
 *{
 *    A b = a; 
 *    freeFunct3(b); 
 *}
 */
void freeFunct3(A& a){
    a.doStuff(); 
}
4

4 に答える 4

6

最初の方法が最適です。呼び出し元がオブジェクトをコピーするか移動するかを選択できるため、呼び出し元がコピーを保持する必要がない場合は、より効率的です。

freeFunct1(a);             // "a" is copied and not changed
freeFunct1(std::move(a));  // "a" is moved and perhaps changed

2 番目も同様ですが、コピーを強制します。

あなたが言うように、3番目は、呼び出し元が引数を変更することを認識しなければならないため、エラーが発生しやすくなります。

于 2013-09-05T08:34:28.897 に答える
3

freeFunct3まず、すでに述べたように、free 関数のセマンティクスがその「自身の」オブジェクトのみを変更することである場合は、実行しないでください。

第 2 に、移動の最適化[C++11]、例外の安全性、潜在的なコード サイズに関連して、freeFunct1との間に違いがあります。freeFunct2

あり(freeFunct2constへの参照による取得):

  1. 常に引数の新しいコピーを作成し、移動することはありません [C++11]。
  2. のコピー構築でA例外がスローされる場合は、関数の本体内でスローされます。
  3. Aのコピー コンストラクターがインライン化されている場合(関数はインライン化されていない場合)、関数の本体内で1 回展開されます (関数が複数の異なる場所から呼び出された場合でも)。

あり(freeFunct1値を取る):

  1. [C++11] Amove コンストラクターがあり、右辺値 (たとえば call freeFunct1(A(args))) を渡す場合、コピーを回避できます。
  2. のコピー (または移動) 構造がA例外をスローする場合、呼び出しサイトでスローします。
  3. Aのコピー (または移動) コンストラクターがインライン化されている場合、各呼び出しサイトで複数回展開されます

または、左辺値/右辺値参照をオーバーロードして、不必要に右辺値をコピーしないようにすることもできます。

void freeFunct4(const A& a){
    A b = a; 
    b.doStuff(); 
}
void freeFunct4(A&& a){
    a.doStuff(); 
}
于 2013-09-05T09:05:53.530 に答える
2

IMO、最初が最高で最後が最悪です。

ただし、かなりの数の人々が、const 参照による受け渡しに慣れすぎて、デフォルトで #2 を書きます。この場合、回避しようとしているコピーが必要な場合でもです。

于 2013-09-05T08:31:27.357 に答える
1

1 つ目は、ローカル コピーのみを変更します。2 番目は 1 番目と同じですが、コードが追加されています。3 番目は、非 const 参照であるaため、呼び出し元に表示されるように変更します。freeFunct3関数の上のコメントのように呼び出された場合、実際には 2 番目のバージョンと違いはありません。

したがって、ローカル コピーを変更したいだけで、それらの変更が呼び出し元に渡されない場合は、最初のバージョンをお勧めします。

于 2013-09-05T08:31:50.000 に答える