Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

配置newとrealloc

タグ: C++ VS2005

mallocで確保し、配置newした領域をreallocして良いか否か。
具体的にコードで示すと

#include <iostream>

class Foo
{
public:
    Foo()
    {
        // 構築時のthisを覚えておく
        _this = this;
    }
    
    bool IamI() const
    {
        // 構築時と同じ記憶域に配置されているか
        return this == _this;
    }
    
private:
    Foo(const Foo&);
    Foo& operator=(const Foo&);

    const Foo* _this;    
};

bool bar()
{
    // Fooオブジェクト2個分のメモリを確保
    Foo* foos = static_cast<Foo*>(malloc(sizeof(Foo) * 2));
    if (! foos)
    {
        return false;
    }

    // 確保したメモリにFooオブジェクトを配置new
    for (int i = 0; i < 2; i++)
    {
        new (foos + i) Foo;
    }

    // Fooオブジェクト1000個分のメモリを再確保
    if (Foo* foos2 = static_cast<Foo*>(realloc(foos, sizeof(Foo) * 1000)))
    {
        foos = foos2;
    }
    else
    {
        for (int i = 0; i < 2; i++)
        {
            foos[i].~Foo();
        }
        free(foos);
        return false;
    }

    // 先頭2個を除いた残りを配置new
    for (int i = 2; i < 1000; i++)
    {
        new (foos + i) Foo;
    }

    // 先頭2個のthisが変化していることを確認
    for(int i = 0; i < 4; i++)
    {
        std::cout << i << ':' << foos[i].IamI() << std::endl;
    }

    // デストラクタを呼び出して解放
    for(int i = 0; i < 1000; i++)
    {
        foos[i].~Foo();
    }
    free(foos);

    return true;
}
0:0
1:0
2:1
3:1

こういった「オブジェクトの記憶域の再配置」は規格で認められているのか否か。
規格書をざっと読んだ限りでは「ダメ」という記述は見当たらないが……オブジェクトが生存している間(=デストラクタが呼ばれていない間)に記憶域を変えるのはなんとなく危険な気がする。

と思ったらVS2005のATL::CArrayはバイト単位のnewと配置newを使ってまさにこんな感じの実装をしていた。
うーん、となるとむしろ「オブジェクトが生成されてから破壊されるまでthisはずっと同じ値を指している」という固定観念を取っ払った方が幸せだろうか。

スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/230-8e45b1c3
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。