0

多くの場合、私はこの状況を見てきました

class Foo
{
    static void* ThreadFun(void* p)
    {
        Derived* args = (Derived*)p;

        //do something with args.
        //example 
        //cout << args->getname();
    }

    void function()
    {
        Base* args = new Derived();
        args->setname("test");

        pthread_t id;
        int ret = pthread_create(&id, NULL, ThreadFun, (void*) args);    
    }
}

まず、それは適切なC ++コードですか?または私は何かが欠けていますか?私はいくつかの読み取りを行いましたが、クラスへのポインタをvoid *にキャストすると情報が失われ、派生クラスでgetname()を呼び出すことは違法になる可能性があります。

私が正しく理解した場合に彼らが示唆するのは、次のようなものです。

void function()
{
    Base* args = new Derived();
    args->setname("test");

    void* pargs = (Base*)malloc(sizeof(*args)); // to be freed in ThreadFun
    pargs = args;
    pthread_t id;
    int ret = pthread_create(&id, NULL, ThreadFun, pargs );    
}

私はそれを本当に理解していません、どうすればこれを適切に行う必要がありますか?

4

1 に答える 1

3

ああ、すごい...いいえ、2番目の例はmalloc()によって割り当てられたメモリをリークします。コメントから、そのアドバイスに従うとnew Derived()、ThreadFunで割り当てをfree()することができます。 malloc()割り当てを解放します。

クラスへのポインタをvoid*にキャストすると、情報が失われます。そうではありません。プレーン&シンプル。それが失うのは、そのポインターが何を意味するかについてのコンパイラーの理解です。それが何を意味するかを知っている場合は、いつでも適切なタイプにキャストして、完全な機能を取り戻すことができます。これは、最初の例とまったく同じです。ThreadFun()関数が新しいスレッドで開始されると、void*を元の型であるDerived*にキャストします。

new Derived()最初に割り当てを呼び出したときに、戻りポインターをタイプのポインターに割り当てたことに気づきましたBase*class Derivedから継承すると仮定しているので、そこでの割り当ては、タイプのポインターである間、クラスの非ポリモーフィックな動作を失うclass Baseという観点から、実際には「情報の損失」を引き起こします。ただし、ThreadFun()で実際の型にキャストし直すまでに、完全な機能が回復します。代わりに、オブジェクトを割り当ててそれを使用して新しいスレッドを起動し、ThreadFun()でそれをにキャストした場合は注意してください。Base*Derivednew BaseDerived*、コンパイラはそれを可能にしますが、未定義の動作があります...おそらくクラッシュします。(pthreadsインターフェースのために)void *を通過する必要があるため、C ++スタイルのキャストを使用しても、型チェックの安全性はありません。したがって、そのvoid *を必要なものに変換することができ、コンパイラーがそれを許可します。しかしもちろん、真に有効なキャストは、(Base*)または(Derived*)、または継承階層内のそれらの間にあるものだけです。

また、void *として、オブジェクトを削除してそのデストラクタを実行することはできません。オブジェクトを削除するには、コンパイラがどのデストラクタを呼び出すかを知るために、そのポインタをどのタイプにでも戻す必要があります。Derivedタイプのクラスへのポインタを使用すると、別の厄介な問題が発生する可能性があります。デストラクタがそうでないBase*場合、そのオブジェクトを呼び出してオブジェクトを削除すると、割り当ては完全に割り当て解除されますが、一部のみが割り当て解除されます。オブジェクトのデストラクタが実行されます.....デストラクタがキーワードで定義されていない限り、オブジェクトを削除することができます。私は自分自身を完全に不明瞭にしましたか?Base::~Base()virtualDeriveddeleteBase*BasevirtualDerivedBase*

于 2012-12-08T06:53:39.640 に答える