22

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

次のクラスがあるとしましょう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はエイリアスになりましたか?

4

3 に答える 3

21

オブジェクト自体のプレフィックスインクリメントをポストフィックスインクリメントで呼び出すのがより慣用的です。

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

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

于 2010-07-05T18:02:46.487 に答える
17

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

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

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

実装の効率は、標準的な実装と同等に見えます。

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

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

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

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

于 2010-07-05T17:34:24.073 に答える
2

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

前置演算子では、X のコピーは作成されません。

後置演算子では、ret に対して 1 つのコピーが作成され、関数から戻るときに別のコピーが作成される可能性がありますが、すべてのコンパイラはこのコピーを省略します。

于 2010-07-05T17:35:07.817 に答える