Effective C++勉強メモ: Item 21 Pass-by-存在しないオブジェクトへのReferenceしてはいけない・・・
前回の項目を理解するとなんでもPass-by-Referenceしたくなるが、ReferenceはそもそもちゃんとReferenceを返した先でも存在し続けるオブジェクトのものでなければならず、その条件が満たせないことも多い。という項目。
例えばA
クラスにoperator*
を定義して以下のような処理を可能にしたいとする:
A a; A b; A c = a * b;
operator*
がconst A
を返すとすると、a * b
で関数内で一度作成されたA
インスタンスを関数から返す時にまたコピーする必要性が生じる。一旦作ったものがあるのだからそれを返せばいい、と:
class A { public: const A& operator* (const A& lhs, const A& rhs); };
のような実装をしてしまいがちだが、その場合関数内で作ったA
インスタンスはstackかheapのどちらかにいることになる。
Stackの場合
関数内でstackに乗せたインスタンスは関数から出る時に回収されるので、Pass-by-Referenceした途端にReferenceされているオブジェクトが消失する。のでダメ。
Heapの場合
const A& operator=(const A& lhs, const A& rhs) { A* result = new A(lhs.n * rhs.n); return *result; }
などとやった場合、たしかにオブジェクトは永続するが、そのおかげで受け取り側がちゃんとdelete
しないとメモリリークになる。
そしてA d = a * b * c;
などのコードの場合、そもそもdelete
できないので絶対にメモリリークになる。
関数内でStaticオブジェクトを保持する
ならそもそも新しいオブジェクトを作成するのではなく、staticなインスタンスを関数の中で使い回せば・・・ と(正直無理筋っぽいことを)考えたなら、それもダメである。
if (a*b == c*d) {...}
が必ずTrueになってしまう。同じインスタンスへのreferenceを比較してるんだからそれはそうだよね。
こういうケースはおとなしくPass-by-Valueしよう。