ヒープとshared_ptr

先日ファイルシステムが壊れてます、みたいなエラーが記録されているのを発見。
ググったらデフラグかけたらエラーがなくなった、みたいな記事を見つけました。

いくらなんでもそれはないだろう・・・と思ったけど・・・、
まぁ、エントロピーが増大しまくっているHDDを久しぶりにデフラグをかけたら
ちょっとは速くなるだろうと思い3時間かけてデフラグ終了。
エラーが記録されているHDDにデフラグをかけるなんて、傷に塩を塗り込む行為だとは思いつつ(^^;

で、今日イベントビューア見たらエラーが消えてました・・・どーなってんの、コレ?(笑)
まぁいいや。

で、本題です。

Windowsで動的にメモリブロックを確保するには、Heap APIを使うか、もっと原始的に?VirtualAlloc()などの仮想メモリを直接確保するAPIを駆使するか・・・と思います。でも仮想メモリを直接いじると何でもできちゃう反面、ちょっと大げさですし・・・。ということで、よほど大きなメモリブロックを確保するほどでもないサイズだとヒープAPIを使用するほうがお手軽です。

そんなの malloc()で十分・・・という感じもしますが・・・ちょっとした備忘録のメモも兼ねています。

で、確保したメモリブロックの寿命管理をスマートポインタ、shared_ptr に任せてしまおう、というわけです。

プライベートヒープを使用する上で、HeapCreate()とHeapDestroy()を呼ばないといけないわけで、ヒープハンドルをいつ廃棄するか(HeapDestroy()を呼ぶか)を参照カウンタで管理したいと思い次のようなコードを思いつきました。

//-----shared_heap.h-------

#include <windows.h>

//shared_ptrはboost版でもいいですが、
//Visual C++ 2008SP1にはTR1の実装があるのでそれを使います。
#include <memory>

using namespace std::tr1;

class shared_heap
{
public:
  typedef std::tr1::shared_ptr<VOID> return_type;

private:
	//CCriticalSectionは CRITICAL_SECTION構造体を単純にラップしたクラスです。
  static CCriticalSection _criticalsection;
  static HANDLE _sHeap;
  static UINT _sCount;
  
  class HeapDeleter
    {
    public:
      void operator()(PVOID ptr)
        {
          _criticalsection.Enter();
          if(::HeapFree(_sHeap,HEAP_NO_SERIALIZE,ptr))
            {
              if((--_sCount == 0) && _sHeap)
                {
                  ::HeapDestroy(_sHeap);
                  _sHeap = NULL;
                }
            }
          _criticalsection.Leave();
        }
    };
  
  shared_heap(){};
  ~shared_heap(){};

public:
  static return_type alloc(size_t size)
    {
      return_type retVal;
      
      _criticalsection.Enter();
      if(!_sHeap)
        _sHeap = ::HeapCreate(HEAP_NO_SERIALIZE,0,0);
      
      retVal = return_type(::HeapAlloc(_sHeap,HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY,size),HeapDeleter());
      _sCount++;
      
      _criticalsection.Leave();
      
      return retVal;
    }
};

CCriticalSection shared_heap::_criticalsection;
HANDLE shared_heap::_sHeap  = NULL;
UINT   shared_heap::_sCount = 0;

この shared_heapクラスは単純に静的関数を集めたもので、インスタンス化しても意味はないのでコンストラクタとデストラクタはプライベートにしています。実際には、各静的メンバ関数およびカスタムデリータの定義(.h)と実装(.cpp)を分ける必要がありますし、静的メンバ変数の初期化は実装側(.cpp)に書く必要もありますねぇ・・・。

で、まぁ、要点はshared_heap::alloc()で、HeapAlloc()APIをコールして得たメモリブロックのポインタをカスタムデリータとともにshared_ptrのコンストラクタに渡して、shared_ptrを返しています。スレッドセーフにするためクリティカルセクションを使用しています。

非常に単純なコードですが、これで廃棄処理コードを書く手間が省けます。shared_ptr 万歳!(^_^;;;

//使用例
#include "shared_heap.h"
int _tmain(int argc,_TCHAR **argv)
{
  shared_heap::return_type sptr = shared_heap::alloc(512);

  //なんかの処理

  return 0;
}

※僕の備忘録ですので、多々間違いがあるかもしれません。誰もいないと思いますが、そのままをコピペして使用するのは危険です。ご了承を。

人間対コンピュータ

チェスでプロを破ったディープブルーの名前は有名ですが、チェスよりはるかに高度で複雑だ、と言われている(どこでか知らんけど)、将棋で、まだコンピュータがプロ棋士を打ち負かしたということは聞いたことがない。知らないだけかもしらないけど。

「情報処理学会が日本将棋連盟に「コンピュータ将棋」で挑戦状」

だそうです。複数のソフトウェアを同時に走らせ、出た結果を集約して次の一手を決める手法で、挑戦するんだそうです。単純に思ったんだけど、なんか・・・ずるい気がしないでもない・・・(笑)

まぁ、それでも、プロ棋士が勝ってコンピュータが「参りました!」 という結果を、ほとんどの人が期待するのではないでしょうか、というか、そうなって欲しいと思いつつ、コンピューターに少し関わりのある仕事をしている私としては、コンピュータが勝って欲しい、と思うのも、正直な話(^^;;;

ああ、やっぱり、人間は偉いね! ・・・となるか、ええ! コンピュータの進化はすごいね! となるか。
でも、忘れて欲しくないのは、コンピュータのハードウェアを開発するのも人間の頭脳だし、ソフトウェアを作るのも人間。

とどのつまり、結局は・・・人間 対 人間 の勝負なんだと。 そんなことを思いつつ、楽しみです(^^

 

 
で、僕はというと、仕事上のトラブルの火消しに(応援に)駆り出されて、珍しく残業が続いて、明日土曜も火消し処理のため仕事です(ーー;;;

明後日は1ヶ月ぶりに撮影会に参加して、ストレス発散の予定(^^;

西尾レイアさん at 09/12/6

そういえば甲子園で高校野球してんですね・・・。電車混んでるのかなぁ・・・。