1

静的メンバー「obj」を含むクラスがあります。静的クラス メンバー obj 自体には静的メンバーが含まれています (クラスのミューテックス型になります)。

私のプログラムが終了すると、クラッシュします。これは、静的オブジェクト 'obj' が破棄されたときに発生します。「obj」のデストラクタは、その静的メンバーを呼び出します (基礎となる低レベル オブジェクトを破壊するために、RAII イディオムに従う私自身のミューテックス タイプ)。残念ながら、静的オブジェクトの初期化順序 (-> 逆のデストラクタ順序) が定義されていないため、このメンバーは既に破棄されています。

これからきれいに生き残る方法は?私はこれがより頻繁に起こっていないことに驚いています。一般に、静的な非 POD メンバーを持つことは非常に危険なようです。特に内部構造をよく知らない場合。

4

3 に答える 3

0

コンストラクタまたはデストラクタで静的オブジェクトによって使用されるオブジェクトが必要な場合は、通常、シングルトン パターンのバリエーションを使用するのが最善です。これにより、初期化の問題の順序が解決されます。正しく行えば、オブジェクトは破棄されないため、破棄の順序の問題も発生しないはずです。

アプリケーションは明らかにマルチスレッド化されているため (mutex があるため)、main に入る前に確実に初期化することにより、オブジェクトをスレッドセーフにする通常の予防策を講じる必要があります。基本的な考え方は次のようなものです。

template <typename T, char const* id>
class StaticInstanceWrapper
{
    static T* myObject;
public:
    static T& instance();
};

template <typename T, char const* id>
T* StaticInstanceWrapper<T, char const* id>::myObject =
        &StaticInstanceWrapper<T>::instance();

template <typename T, char const* id>
T& StaticInstanceWrapper<T>::instance()
{
    if ( myObject == NULL ) {
        myObject = new T;
    }
    return *myObject;
}

次に、静的オブジェクトを として定義し、だけではなく static StaticInstanceWrapper<Whatever> obj;としてアクセスします (メンバーがないため、コンパイルされません)。obj.instance().someFunction()obj.someFunction()objsomeFunction()

のインスタンスごとStaticInstanceWrapperに異なる型を持ち、一意の静的メンバーを持つには、テンプレートの個別のインスタンス化を強制する必要があることに注意してください。idこれが、テンプレート引数を使用する理由です。この引数の型は、各インスタンスが一意の識別子を持っている限り、実際には何でもかまいません。実際には、おそらく定義にマクロを使用します。次のようなものです。

#define DEFINE_STATIC_INSTANCE_WRAPPER(type, name) \
char const PASTE(name, _Identifier)[] = STRINGIZE(name); \
StaticInstanceWrapper<type, PASTE(name, _Identifier)> name

これにより、各インスタンスが一意の ID を持つことが保証されます。(より手の込んだものにしたい場合は、マングルすることもできますが__LINENO__、名前はスコープ内で一意でなければならないため、これが必要であるとは思えません。)

于 2012-11-24T17:39:31.493 に答える
0

それらstaticを関数内に作成すると、関数を最初に呼び出した人に基づいてライフタイムが順序付けられます。これは、シングルトンが実装される傾向がある方法です。

foo& get_foo() {
  static foo instance;
  return instance;
}

bar& get_bar() {
  static bar instance;
  return instance;
}

ただし、静的を避ける方が本当に良いです。

于 2012-11-24T16:58:17.577 に答える
0

これは、動的割り当てを回避しようとするときによくある落とし穴です。

この問題を回避する方法は、「静的クラス」のパターンに従うことです。通常、静的データは、静的データを持たないインスタンスの「マネージャー」クラスに属します。静的データの初期化は、明示的な「初期化」呼び出しで処理され、破棄は、静的データと静的メンバー関数のみを持つマネージャー クラスの明示的な「シャットダウン」呼び出しで処理されます。

new または delete を使用して、何をしているのかを明示する必要がある場合があります。この意味で、自動メカニズムが自動的に機能する利点を無効にしますが、代わりに、信頼でき、デバッグが容易な初期化およびシャットダウン ルーチンを取得できます。

このアプローチは本質的にシングルトンを作成するため、マネージャー クラスのインスタンスはありません。基本的には、静的データのロードと、カプセル化の利点を提供するクラス構文を備えたいくつかの C 関数です (たとえば、プライベート メンバーはクラスの外部からアクセスできません)。

これは、すべてのデータがどこにあり、それをどう処理するかを知っているため、多くの場合、コンパイラにとっても使いやすいです。

于 2012-11-24T16:58:27.030 に答える