9

C++ 演算子に関するウィキペディアの記事に行くと、例として次のようになります。

Addition : a + b -> T T::operator +(const T& b) const;

したがって、演算子は T 型の非 constを返します。このガイドラインを見ると、作成者は次の構文を避けるために戻り値の型をconstにする必要があると述べています。

(a+b) = c

ここで、この構文が気にならないと仮定し、a と b が大きな配列であると考えてください。「純粋な」パフォーマンスの観点から、戻り値の型に const キーワードがない場合、コンパイラ (g++ および -O3 を使用した intel icpc) からの最適化を防ぐことができますか? 答えが「はい」の場合、その理由は?

4

3 に答える 3

7

これは興味深い質問です。C++03 では、2 つのオプションのいずれかを使用して最適化するより良い機会はなく、スタイルの選択の問題になります (私自身、constありそうもないエラーを回避するために完全に返されるとは信じていません)。

一方、C++11 では、実際に影響がある可能性があります。特に、タイプが移動操作をサポートし、戻り値からのコピー/移動を省略できない場合は、constあなたが返すことで効果的に移動を無効にします*

// T is move assignable, with the usual declaration of a move assignment operator
T f();
const T g();
int main() {
   T t;
   t = f();     // can move
   t = g();     // cannot move!!!
}

あなたの特定のケースでは、大きな配列があなたにとって何を意味するかによって異なります。それらがstd::arrayそうである場合(または自動ストレージを備えた配列)、移動できないため、とにかくこれはオプションではありませんが、大きな配列が動的に割り当てられている場合メモリ、移動はコピーよりもはるかに効率的です。C++11 では、パフォーマンスの低下を引き起こす可能性があるのは、存在しないのではなく、存在することに注意してください。const


*これは100% trueではありません。移動代入演算子が への右辺値参照によって引数を取得した場合、移動できますconst。しかし、標準ライブラリの型はどれもこのように引数を取らず、人々がそれを行うことも期待していません (移動const_cast操作 (コンストラクター/代入のいずれか) 内で必要であり、意味がありません:それから移動(盗む) しているのに、なぜそれを変更しないと主張するのですか??

于 2012-08-12T03:07:34.587 に答える
2

type の一時的な右辺値インスタンスを返すためT、このステートメントは、 type のデータ メンバーである静的変数への変更など、割り当て操作にグローバルな副作用がない限り、何もしません。Tターミナルへの出力、など。したがって、タイプによって、および代入演算子がコンパイラのデフォルトの代入演算子であるかどうかによって、この操作全体が最適化パスで安全に省略される場合があります。type にユーザー定義の代入演算子がある場合T、代入操作は省略されませんが、前述のように、グローバルな副作用がない限り、これはステートメントの実行の有効期間を過ぎて何もしません。の値を保存していないためc名前付きでアクセス可能なメモリ位置に存在するオブジェクト。

戻り値のT型を として宣言しconst、オペレーター メソッドがconstクラス メソッドではない場合、特定のタイプのオペレーター チェーンが無効になることに注意してください。効果。例えば:

(a+b).print(); //assuming print() is non-const method

またはクラスメソッドでoperator+はないと仮定 すると、const

d = (a+b) + c;
于 2012-08-12T02:26:30.973 に答える
0

operator +メンバー関数として実装しないでください。operator +=constではないことを実装するだけです。次に、を処理するグローバル関数を提供しoperator +ます。これが最も一般的な方法だと思います。

T& T::operator +=(const T& t)
{
    // add t to object ...
    return *this;
}

T operator +(T t1, const T& t2)
{
    t1 += t2
    return t1; // RVO will eliminate copy (or move constructor)
}
于 2012-08-12T07:52:11.503 に答える