ikautak.log

C/C++, Python, CUDA, Android, Linux kernel, Network, etc.

More Effective C++ 項目27 ヒープ上のオブジェクトへの要求と禁止

新訂版 More Effective C++ (AddisonーWesley professional co)

新訂版 More Effective C++ (AddisonーWesley professional co)

  • 作者: スコット・メイヤーズ,安村通晃,伊賀聡一郎,飯田朱美,永田周一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2007/06/29
  • メディア: 単行本(ソフトカバー)
  • 購入: 8人 クリック: 129回
  • この商品を含むブログ (43件) を見る

項目27 ヒープ上のオブジェクトへの要求と禁止

いつでもオブジェクトが破棄できるように、確実にヒープ上にオブジェクトを割り当てたいときと、逆に、メモリリークがないようにヒープに割り当てたくない、というときのテクニック。

ヒープ上のオブジェクトへ要求する(←これ多分訳おかしいだろ)

ヒープ上にしかオブジェクトを生成できないようにするには、new以外の方法ではオブジェクトを生成できなくする。

ヒープ外のオブジェクトは自動的に生成され、破棄されるので、これらの暗黙の生成と破棄を禁止する。
コンストラクタとデストラクタをprivateにすればできるが、デストラクタだけでよい。

class UPNumber {
public:
    UPNumber();
    UPNumber(int initValue);
    UPNumber(double initValue);
    UPNumber(const UPNumber& rhs);

    void destroy() const { delete this; } // 擬似デストラクタ
    ...

private:
    ~UPNumber();
};

そうすると以下のようになる。

UPNumber n;                 // NG! 後でnのデストラクタが暗黙で呼ばれる

UPNumber* p = new UPNumber; // OK

delete p;                   // NG! デストラクタはprivate

p->destroy();               // OK

オブジェクトがヒープ上にあるかどうかを判断する

オブジェクトがヒープ上に作られたかどうかを知る方法として、operator newが呼ばれたかどうかで判断するとまずい。
operator new[]が使用されたとき、複数のオブジェクトが作られコンストラクタも複数回呼ばれるが、メモリ割り当ては1回だけだから。

bool onHeap(const void* address)
{
    char onTheStack;
    return address < &onTheStack;
}

このようにスタックのアドレスとオブジェクトのアドレスを比較してヒープ上かどうかを判断するのもまずい。
staticなオブジェクトなどが割り当てられる場所はシステム依存のため、スタックより前とは限らない。

オブジェクトがヒープ上にあるかどうかを気にする必要がないように、ソフトウェアを設計しなければならない。

ヒープ上のオブジェクトの禁止

operator newをprivateにすることで、クライアントにnew演算子を呼び出せなくすることができる。

class UPNumber {

private:
    static void* operator new(size_t size);
    static void operator delete(void *ptr);
    ...
};

こうすると、以下のようにnewだけ禁止できる。

UPNumber n1;                // OK

static UPNumber n2;         // OK

UPNumber* p = new UPNumber; // NG! operator newはprivate