0

プログラムの終了時に Visual C++ ランタイムがオブジェクトを破棄するタイミングに関連する、やや厄介な問題に出くわしました。

特定の状態への参照が有効であることを確認するために使用されるクラスがあります。未知の期間、状態を保存する必要があります。この間、状態は破棄される可能性があり、使用できませんshared_ptr。だから私は使う

class MyClass
{
private:   
    static std::list<MyClass*> make_list();
    static std::list<MyClass*> refed_list;          
    static void StateClosed(B* state);

public:
    B* state;
    MyClass(B* state);
    virtual ~MyClass();

    bool still_valid() const;
 };

の各インスタンスはMyClass、自身をコンストラクターに追加refed_listし、デストラクターで自身を削除します。カプセル化された状態が閉じている場合、MyClassに通知さrefed_listれ、カプセル化インスタンスをチェックし、そのポインタを無効にします。これは実際には関係ありません。重要なことは、a を使用してstatic listおり、コンストラクター/デストラクタでこのリストにアクセスすることです。が定義さrefed_listれているファイルで初期化します。MyClass

さて、問題..私のプログラムがランタイムを閉じると、refed_listある時点でランタイムがクリーンアップされ、その後、のインスタンスがクリーンアップされ、MyClassそれらのデストラクタが呼び出されます。refed_list次に、すでにクリーンアップされているものにアクセスしようとします。これにより、反復子が正しくなくなり、未定義の動作が発生します。この場合は、デバッグ アサーションの失敗です。

この問題を回避する方法はありますか? 異なるコンパイル単位のどの順序オブジェクトが破棄されるかを指定できるとは思えませんが、refed_listまだ有効かどうかを確認する方法はありますか? 現時点では、動作するかどうかを確認refed_list.size() == 0していますが、これの動作も未定義です (と思いますか?)。

4

2 に答える 2

2

refed_list起動時に初期化されるポインターをいつでも作成できます。そうすれば、それは決してクリーンアップされません。(そして、プロセスが終了すると、使用するメモリは OS によって回復されます。)

それがより深い設計上の問題を回避するためのハックのように聞こえる場合は、おそらくそうです。:)

于 2013-02-24T11:31:39.360 に答える
0

私はこれが真実ではないと思います:

プログラムを閉じると、ランタイムはある時点でrefed_listをクリーンアップし、その後、MyClassのインスタンスをクリーンアップして、デストラクタを呼び出します。

ランタイムは確かにリストをクリーンアップしますが、リスト内のオブジェクトはポインターであるためクリーンアップしません。これを行う唯一の方法は、shared_ptrのようなスマートポインタクラスを使用することです。それでも、そうすると、オブジェクトはリストが破棄されている間にリストにアクセスしようとします。これは未定義の動作かどうかはわかりませんが、確かに不安定なようです。

おそらく、オブジェクトが格納されているリストを参照する必要がないように、または少なくともリストが破棄される前に(つまり、list ::〜listが呼び出される前に)再設計する必要があります。 。

于 2013-02-24T11:08:14.570 に答える