1

単純な C++ クラスで奇妙な動作に遭遇しました。

classA.h

class A
{
public:
  A();
  ~A();
  static const std::string CONST_STR;
};

classA.cpp

#include "classA.h"
#include <cassert>

const std::string A::CONST_STR("some text");

A::A()
{
  assert(!CONST_STR.empty()); //OK
}

A::~A()
{
  assert(!CONST_STR.empty()); //fails
}

main.cpp

#include <memory>  
#include <classA.h>  

std::auto_ptr<A> g_aStuff; 

int main() 
{ 
  //do something ... 
  g_aStuff = std::auto_ptr<A>(new A()); 
  //do something ... 
  return 0; 
}

アクセス違反などは予想できますが、静的な const 文字列の内容が変更される可能性があるとは予想していません。ここにいる誰かが、そのコードで何が起こっているのかをよく説明していますか?

ありがとう、ノーバート

4

7 に答える 7

3

編集:明らかに、欠落A::はコードの元の投稿のタイプミスでした。

元の回答:

持つということですか


    const std::string A::CONST_STR("some text");

CONST_STR がクラスの一部になるようにA

それ以外の場合は、それを個別に宣言し、の静的メンバーを初期化していませんA

于 2009-06-19T12:50:30.527 に答える
2

アクセス違反などは予想できますが、静的な const 文字列の内容が変更される可能性があるとは予想していません。

未定義の動作: 未定義です。CONST_STR が破棄されている場合、それにアクセスしてもハードウェア例外は保証されません。クラッシュする可能性がありますが、そのアドレスには空の文字列のように見えるデータが含まれる可能性があります。そのデストラクタはポインターなどをクリアする可能性があります。

この場合、A インスタンスは、main() で割り当てられたグローバル スマート ポインターにも格納されていると言えます。したがって、CONST_STR は、A コンストラクターでアクセスされたときに構築されていますが、スマート ポインターが破棄される前に破棄される可能性が非常に高くなります。確かに言うには、プログラム全体が必要です。

[編集:あなたはそれをしました。CONST_STR と g_aStuff は異なるコンパイル単位で定義されているため、それらの相対的な構築順序は標準では定義されていません。CONST_STR が最初に破棄されていると推測しています。]

于 2009-06-19T13:00:20.570 に答える
2

2 つの異なるコンパイル単位で 2 つの静的変数を作成しています。それらがどの順序で初期化されるかを知る方法はありません。ただし、それらのデストラクタは常に逆の順序で呼び出されます。

あなたの場合、次のシナリオが発生したようです:

g_aStuff constructor 
CONST_STR constructor

main funciton initializes g_aStuff

CONST_str destructor 
g_aStuff descrutor  

この時点で CONST_STR.empty() の結果は未定義です。アサートをトリガーする可能性があります。

于 2009-06-19T12:53:50.287 に答える
1

標準では、異なる翻訳単位でのグローバル/静的オブジェクトの初期化の順序は指定されていません。ただし、そのような各オブジェクトは、その翻訳単位の関数が実行される前に初期化されることが保証されます。

あなたの場合、CONST_STR後で初期化されg_aStuff、破壊の順序が構築の順序と逆であるため、それより前に破壊されることが起こります。したがって、のデストラクタCONST_STRからアクセスすると、A未定義の動作が呼び出されます。アクセス違反が発生する場合と発生しない場合があります。

CONST_STRただし、Aこれらは同じ翻訳単位にあるため、 のコンストラクターが実行される前に初期化されます。

于 2009-06-19T13:04:38.830 に答える
1

const std::string CONST_STR("some text");
classA.cpp で定義されているのは A のメンバーではありません。その定義は次のようになります。

const std::string A::CONST_STR("some text");
于 2009-06-19T12:51:40.777 に答える
0

完全なコードを見ると、コンパイル ユニット (classA.cpp と main.cpp) 間の破棄の順序に依存しています。main でローカルとして g_aStuff を作成すると、アサートがパスするはずです。

于 2009-06-19T13:03:19.287 に答える
0

A のグローバル インスタンス (または型 A の静的クラス メンバー) がある場合に発生する可能性があります。グローバルとスタティックの初期化の順序は定義されていないため (相互変換単位)、定義される可能性があります。

于 2009-06-19T12:47:45.073 に答える