0

私が理解したように、クラスは、それらが同一である限り、複数の変換単位で定義できます。そのことを念頭に置いて、次の例を検討してください。

 //1.cpp

class Foo{
 public:
  int i;
};


void FooBar();

void BarFoo(){
  Foo f;
}


int main(){
 FooBar();
 BarFoo();
}

//2.cpp

class Foo{
 public:
  std::string s;
};

void FooBar(){
  Foo f;
}

これはコンパイルされ、クラッシュは発生しません。

次の変更を行う場合:

//1.cpp
 Foo FooBar();
//2.cpp
 Foo FooBar(){
   Foo f;
   return f;
 }

クラッシュします。一方がクラッシュし、もう一方がクラッシュしないのはなぜですか。また、最初の例ではODRに違反していませんか?私がそうなら、なぜそれはうまくコンパイルされるのですか?

4

2 に答える 2

1

あなたが述べた理由により、プログラムは形式が正しくありません。コンパイラーは診断を必要としませんが、形式の悪いプログラムでクラッシュする理由を議論する意味がありません。

それでも、やってみましょう:

FooBarの動作はの実行に影響を与えないため、最初の例はおそらくクラッシュしませんmain。メソッドが呼び出され、何かを実行します。それだけです。

2番目の例では、を返そうとしますFoo。で定義されFooBarたのバージョンを返します。に表示されるので、で定義されたバージョンを想定しています。これは完全に異なるバージョンであり、メンバー、サイズが異なります。デストラクタが破損する可能性があります。(単なる推測)Foo2.cppmain1.cppFoo1.cpp

編集:これは1つの定義規則に違反します:

3.21つの定義ルール[basic.def.odr]

6)各定義が異なる翻訳単位で表示され、定義が次の要件を満たしている場合、プログラムにはクラスタイプ[...]の定義が複数存在する可能性があります。[...]

  • Dの各定義は、同じトークンのシーケンスで構成されます。

[...]

于 2012-10-12T23:51:24.667 に答える
0

コンパイラ/リンカーの動作は次のとおりです。

  1. コンパイラは、提供されているヘッダーを持つcppファイルを変換します。.objファイルを生成します。あなたの場合、o.bjファイルにはdata-structへの参照がありますFoo。そして、他の詳細はありません。

  2. リンカは.objファイルをリンクします。文字列名のみを比較します。あなたのobjファイルには同じものがありますFoo。名前が一致します。リンカの場合、これは同じことです。

  3. その後、プログラムを開始します。ほとんどの場合、クラッシュします。具体的には、未定義の動作を示します。無限ループに入ったり、奇妙なメッセージを表示したりする可能性があります。

cppファイル内の同一のヘッダーまたは定義をすべてのcppファイルの翻訳に提供するのはユーザーの責任です。既存のソフトウェアツールではこれを確認できません。これがその仕組みです。

于 2012-10-13T00:12:16.183 に答える