7

私は VC9 で構築されたアプリケーションに取り組んでいますが、完全には理解できない警告に出くわしました: コンストラクターの右中括弧に「到達不能コード」という警告があるのはなぜですか?

問題を再現するための最小限のテストケースは次のとおりです。

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
    foo();
  } // d:\foo.cpp(7) : warning C4702: unreachable code
};
int main() {
  A a;
}

警告をトリガーするには、これを /W4 でコンパイルする必要があります。または、/we4702 でコンパイルして、この警告の検出時にエラーを強制することもできます。

d:\>cl /c /W4 foo.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.21022.08 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

foo.cpp
d:\foo.cpp(7) : warning C4702: unreachable code

誰かがここで到達できないものを正確に説明できますか? 私の最善の理論は、それがデストラクタであるということですが、決定的な答えが欲しいです.

このコードの警告をクリーンにしたい場合、どうすればそれを達成できますか? 私が思いつく最善の方法は、これをコンパイル時のエラーに変換することです。

struct A {
private:
  A(); // No, you can't construct this!
};
int main() {
  A a;
}

編集:明確にするために、noreturn関数でプログラムを終了しても、通常、その関数呼び出しを囲む閉じ中括弧で到達不能コードの警告は発生しません。

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
  }
  ~A() {
    foo();
  }
};
int main() {
  A a;
}

結果:

d:\>cl /c /W4 foo3.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.21022.08 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

foo3.cpp
4

4 に答える 4

3

ゴルピックは正しい軌道に乗っています。私は 2 つの同様のテスト ケースを作成し、それらをコンパイルして逆アセンブルし、根本的な理由を理解するようになったと思います: コンストラクターは常に return ステートメントを暗黙的に生成し、この return ステートメントは noreturn 関数のために到達できません。

noreturn_constructor.cpp

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
    foo();
  }
  ~A() {
  }
};
int main() {
  A a;
}

noreturn_destructor.cpp

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
  }
  ~A() {
    foo();
  }
};
int main() {
  A a;
}

diff -u *.disasm

--- noreturn_constructor.disasm 2012-05-30 11:15:02.000000000 -0400
+++ noreturn_destructor.disasm  2012-05-30 11:15:08.000000000 -0400
@@ -2,7 +2,7 @@
 Copyright (C) Microsoft Corporation.  All rights reserved.


-Dump of file noreturn_constructor.obj
+Dump of file noreturn_destructor.obj

 File Type: COFF OBJECT

@@ -35,15 +35,15 @@

 ??0A@@QEAA@XZ (public: __cdecl A::A(void)):
   0000000000000000: 48 89 4C 24 08     mov         qword ptr [rsp+8],rcx
-  0000000000000005: 48 83 EC 28        sub         rsp,28h
-  0000000000000009: E8 00 00 00 00     call        ?foo@@YAXXZ
-  000000000000000E: 48 8B 44 24 30     mov         rax,qword ptr [rsp+30h]
-  0000000000000013: 48 83 C4 28        add         rsp,28h
-  0000000000000017: C3                 ret
+  0000000000000005: 48 8B 44 24 08     mov         rax,qword ptr [rsp+8]
+  000000000000000A: C3                 ret

 ??1A@@QEAA@XZ (public: __cdecl A::~A(void)):
   0000000000000000: 48 89 4C 24 08     mov         qword ptr [rsp+8],rcx
-  0000000000000005: C3                 ret
+  0000000000000005: 48 83 EC 28        sub         rsp,28h
+  0000000000000009: E8 00 00 00 00     call        ?foo@@YAXXZ
+  000000000000000E: 48 83 C4 28        add         rsp,28h
+  0000000000000012: C3                 ret

   Summary

到達不能コードは、デストラクタではなくコンストラクタで生成されるこの暗黙の return ステートメントです。

-  000000000000000E: 48 8B 44 24 30     mov         rax,qword ptr [rsp+30h]
+  0000000000000005: 48 8B 44 24 08     mov         rax,qword ptr [rsp+8]
于 2012-05-30T15:25:40.967 に答える
2

の最後に呼び出されるデストラクタはないA::A()ので、それは問題ではありません。到達できないのは、コンストラクターが実行を終了した後に発生するオブジェクトの実際の構築です。決して終わらないため、コンパイラが生成したコードには到達できません。

于 2012-05-30T14:54:59.423 に答える
1

fooのdeclspec(noreturn)がこの警告を生成しています。この関数が返されないことをコンパイラーに伝えています。そのため、コンパイラーは、コンストラクターが決して完了しないという警告を出します。

于 2012-05-30T14:45:26.643 に答える
1

http://msdn.microsoft.com/en-us/library/k6ktzx3s(v=vs.80).aspxを参照してください

「この__declspec属性は、関数が返されないことをコンパイラーに通知します。その結果、コンパイラーは、__ declspec(noreturn)関数の呼び出しに続くコードに到達できないことを認識します。」

閉じ中括弧は、到達しないコード(デストラクタの呼び出しなど)を生成する場合があります。

于 2012-05-30T14:45:46.160 に答える