ikautak.log

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

More Effective C++ 項目26 クラスのオブジェクトの数を制限する

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

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

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

項目26 クラスのオブジェクトの数を制限する

25-31はソースコードが多いな…

オブジェクトを1個以下に制限する

コンストラクタをprivateにすることでオブジェクトが生成されないようにできる。

class A {
private:
    A();
    A(const A&);
    ...
};

特定の場合に、生成不可の制限をとることができる。
friendを使ってオブジェクトを返す関数を作る場合。

class Printer {
public:
    void submitJob(const PrintJob& job);
    ...

friend Printer& thePrinter();

private:
    Printer();
    Printer(const Printer& rhs);
    ...
};

Printer& thePrinter()
{
    static Printer p;
    return p;
}

メンバ関数を使う場合。

class Printer {
public:
    static Printer& thePrinter();
    ...
};

Printer& Printer::thePrinter()
{
    static Printer p;
    return p;
}

関数の中のstaticの場合、関数が実行されなければオブジェクトは生成されないが、クラス内のstaticオブジェクトは使用されなくても生成・破棄される。

オブジェクト生成のための文脈

オブジェクトは3つの文脈で存在することがある。

  1. それ自身が生成されたとき
  2. 生成された派生オブジェクトの規程クラス部分であるとき
  3. 他のオブジェクトに含まれるとき

2.は非公開コンストラクタで派生クラスを生成できないようにすると防げる。

オブジェクトの行き来を許す

staticなオブジェクトを使うと、1つしか生成できない上、

Printerオブジェクトp1の生成;
p1の利用;
p1の削除;
Printerオブジェクトp2の生成;
p2の利用;
p2の削除;

のようなことができないため、コンストラクタでオブジェクトの数を数えて制限する。

class Printer {
public:
    class TooManyObjects{};

    static Printer* makePrinter();
    ...

private:
    static size_t numObjects;
    Printer();

    Printer(const Printer& rhs); // コピー禁止のため定義しない
};

size_t Printer::numObjects = 0;

Printer::Printer()
{
    if (numObjects >= 1) { // ここの数でオブジェクト数を制限できる
        throw TooManyObjects();
    }

    ++numObjects;
}

Printer* Printer**makePrinter()
{
    return new Printer;
}

オブジェクト出現回数計測のための基底クラス

オブジェクトの数を制限したいクラスがたくさんあった場合のために、オブジェクト数制限機能をもったクラステンプレートを使う。

template<class BeingCounted>
class Counted {
public:
    class TooManyObjects{};
    static int objectCount() { return numObjects; }

protected:
    Counted();
    Counted(const Counted& rhs);
    ~Counted() { --numObjects; }

private:
    static int numObjects;
    static int maxObjects;

    void init();
};

template<class BeingCounted>
Counted<BeingCounted>::Counted()
{
    init();
}

template<class BeingCounted>
Counted<BeingCounted>::Counted(const Counted&)
{
    init();
}

template<class BeingCounted>
void Counted<BeingCounted>::init()
{
    if (numObjects >= maxObjects) throw TooManyObjects();
    ++numObjects;
}

Countedテンプレートを使ったPrinterクラス

class Printer : private Counted<Printer> {
public:
    static Printer* makePrinter();
    static Printer* makePrinter(const Printer& rhs);
    ~Printer();

    void submitJob(const PrintJob& job);
    ...

    using Counted<Printer>::objectCount;    // クライアントにPrinterオブジェクト数と、
    using Counted<Printer>::TooManyObjects; // 例外を見せるため

private:
    Printer();
    Printer(const Printer& rhs);
};

オブジェクト数のMaxを設定するには

int Counted<Printer>::maxObjects = 10;

のようにする。