Arantium Maestum

プログラミング、囲碁、読書の話題

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しよう。