web-dev-qa-db-ja.com

プレフィックス/ポストフィックスインクリメント演算子

値渡しと参照渡しを正しく理解していることを確認したいと思います。特に、オブジェクトのインクリメント++演算子のプレフィックス/ポストフィックスバージョンを調べています。

次のクラスXがあるとしましょう。

class X{
private:
    int i;
public:
 X(){i=0;}
 X& operator ++ (){ ++i; return *this; } //prefix increment

 X operator ++ (int unused){ //postfix increment
  X ret(*this);
  i++;
  return ret;
 }

 operator int(){ return i; } //int cast
};

まず、プレフィックス/ポストフィックスインクリメント演算子を適切に実装しましたか?

第二に、プレフィックス演算子と比較して、ポストフィックス演算子はどのくらいメモリ効率が良いですか?具体的には、演算子の各バージョンが使用されるときに、いくつのXオブジェクトコピーが作成されますか?

参照によるリターンと値によるリターンで何が起こるかを正確に説明すると、理解に役立つ場合があります。


編集:たとえば、次のコードで...

X a;
X b=a++;

... aとbはエイリアスになりましたか?

22
Cam

これは正しい実装です。インクリメントを行う前に別のコピーを作成する必要があるため、後置演算子のパフォーマンスが低下するのが一般的です(これが、何か他のものが必要でない限り、常にプレフィックスを使用する習慣になっている理由です)。

参照による戻りを使用すると、現在のオブジェクトへのl値参照を返します。コンパイラは通常、現在のオブジェクトのアドレスを返すことによってこれを実装します。つまり、オブジェクトを返すのは、数値を返すのと同じくらい簡単です。

ただし、値による戻りでは、コピーを実行する必要があります。これは、(アドレスだけでなく)リターン中にコピーする情報と、呼び出すコピーコンストラクターがあることを意味します。ここで、パフォーマンスのヒットが発生します。

実装の効率は、通常の実装と同等に見えます。

編集:あなたの補遺に関しては、いいえ、それらはエイリアスではありません。 2つの別々のオブジェクトを作成しました。値で返す場合(および接尾辞インクリメント演算子内から新しいオブジェクトを作成した場合)、この新しいオブジェクトは別のメモリ位置に配置されます。

ただし、次のコードでは、aとb areエイリアス:

 int a = 0;
 int& b = ++a;

bはaを参照するアドレスです。

17
Shirik

接頭辞の増分オブジェクト自体のを接尾辞の増分で呼び出す方が慣用的です。

X operator++(int)
{
    X copy(*this);
    ++*this;         // call the prefix increment
    return copy;
}

したがって、Xオブジェクトをインクリメントするロジックは、プレフィックスバージョン内にのみ含まれます。

20
fredoverflow

演算子は正しく実装されています。

プレフィックス演算子では、Xのコピーは作成されません。

接尾辞演算子では、ret用に1つのコピーが作成され、関数から戻るときに潜在的に別のコピーが作成されますが、すべてのコンパイラーはこのコピーを削除します。

2
Peter Alexander