スレッド関数内の auto 変数

初回ということで、 id にちなんで std::auto_ptr で痛い目に遭った経験を。

どのくらい有名な話かわからないのですが、 _endthread() などをスレッド関数の中から呼び出した場合、スレッド関数のスコープ内にある auto 変数は解放されません。つまり、 auto_ptr または自作スマートポインタが機能しなくなるのです。ローカル変数の解放をスマートポインタに任せていると全てリークします。

サンプルコード

#include <stdio.h>
#include <process.h>
#include <memory>

class Test {
public :
    Test() { printf( "Test new\n" ); }
    virtual ~Test() { printf( "Test delete\n" ); }
};

void testThread( void* param ) {
    std::auto_ptr< Test > test( new Test );

    _endthread();
}

void main() {
    _beginthread( testThread, 0, NULL );

    getchar();
}

実行結果

Test new

このように、 Test クラスのデストラクタは実行されません。スレッド終了に _endthreadex() / ExitThread() を使った場合も同様です。

対策として最も楽な方法は、スレッド関数の中でスコープを切ってやることです。

void testThread( void* param ) {
    {
        std::auto_ptr< Test > test( new Test );
    }

    _endthread();
}

実行結果

Test new
Test delete

こうすれば、 _endthread() 前にスコープの終了が来るので、その時点でスマートポインタが解放されます。つまり、スレッド終了関数をコールする前に必ずスコープを切っておけば OK です。
なお、「スレッド関数の中で goto を使っている場合はどうすればいいか」は考えていませんので悪しからず。スマートポインタと goto を併用するような真似はやめましょうとしか言えません。