プログラミング言語

C++

MS による拡張

メモ

クラスを new させたくない場合

コンストラクタを private (又は protected) にする。

class CantNewSample {
private:
    CantNewSample() {}
}

スライスに気をつける

  • C++ ではインスタンスを、ポインタ(又は参照)とメモリ構造そのものとの両方で扱えてしまう。
    • ポインタ(又は参照)で受け渡しすると、参照渡しとなる。
    • メモリ構造として受け渡しすると、値渡しとなる。
      • 親クラスとして値渡しで受け取ると、拡張したフィールドの情報が失われる。(スライス)
class Foo
{
    int x;
}
class Bar : Foo
{
    int y;
}
void f()
{
    Bar bar;
    ...
    Foo foo = bar; // スライス
}

参照を使うのが手軽な解決。

Foo& foo = bar;

一時オブジェクトによるデストラクタの2回呼び出しに気をつける

  • リソースを持っていて、デストラクタで解放するようなケースではうっかり解放してしまう場合がある。
  • リソースの所持権を渡すような工夫が必要。
static int serial = 1;
class X
{
    int n;
public:
    X() { n = serial++; printf("%p X::X()\n", this); }
    ~X() { printf("%p X::~X() %d\n", this, n); }
};

void foo() 
{
    printf("foo()\n");
    throw X();
}

void bar() 
{
    printf("bar() start \n");
    try
    {
        printf("calling foo()\n");
        foo();
    }
    catch (X& e)
    {
        printf("bar catch\n");
    }
    printf("bar() end\n");
}
bar() start
calling foo()
foo()
0012FCCC X::X()
0012FCCC X::~X() 1 ←本来の生存期間を抜けたので破壊
bar catch
0012FCC0 X::~X() 1 ←コピーされた一時オブジェクトが生存期間を抜けたので破壊
bar() end

一時オブジェクトは作られない場合もある。ただし、実装依存のはず。(最適化の1つ) 動いているからと言って安心してはならない。

static int serial = 1;
class X
{
    int n;
public:
    X() { n = serial++; printf("%p X()\n", this); }
    ~X() { printf("%p ~X() %d\n", this, n); }
};

X foo() 
{
    printf("foo()\n");
    return X();
}

void bar() 
{
    printf("bar() start \n");
    X x = foo();
    printf("bar() end\n");
}
bar() start
foo()
0012FE8C X::X()
bar() end
0012FE8C X::~X() 1

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-08-19 (水) 04:50:42 (388d)