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 
+7

あなたは 'foo()'でプログラムを終了させるので? – juanchopanza

+0

'private'を作り、それを実装しないのが普通の方法です。** C++ 11 **はそれを達成するために' = delete'を持っています。 –

+1

は 'foo()'を '__declspec(noreturn)'にする必要がありますか? – ixe013

答えて

3

Gorpikは正しい軌道にあります。私は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 @@ 

[email protected]@[email protected] (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  [email protected]@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 

[email protected]@[email protected] (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  [email protected]@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] 
1

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

+0

元の質問であまりにも漠然としているかもしれませんが、私は答えで探しているものの本質を捉えていないと思います。なぜなら、終了前にnoreturn関数を呼び出すコンストラクタは、他の関数を終了する前に同じnoreturn関数を呼び出すと、到達できないコードの警告になりますか? – mrkj

1

http://msdn.microsoft.com/en-us/library/k6ktzx3s(v=vs.80).aspx

が「この__declspec属性は、関数が戻らないことをコンパイラに伝えます。その結果、コンパイラは__declspec(noreturn)関数の呼び出し次のコードが到達不能であることを知っています。」を参照してください。

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

+1

この場合、生成されたコードに到達できないことについて、具体的に説明できますか?問題は**正確には、到達不可能な**(「__declspec(noreturn)は何を意味するのか」ではない)でした。この場合、デストラクタ用に生成されるコードはありません。デストラクタは何をしていますか?デストラクタのコードがコンストラクタの閉じ括弧に属しているのはなぜですか? – mrkj

+0

あなたが正しいです、説明はあまりにも単純です。コードの逆アセンブリを見ると、閉じ括弧は、デストラクタと同じコードをコンストラクタに対して正確に生成します。だから私の理解のために、警告は両方のケース(私が期待していないだろう)で生成されなければならない。ところで、通常(または仮想)メソッドも警告を生成しません。 – Stefan

2

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

+1

私はそれが興味深い理論だと思います。コンストラクタのユーザ指定の本体のほかに、「オブジェクトの実際の構成」を構成するために生成されるコードは何ですか? – mrkj

+1

ユーザー定義のコンストラクタの後に実行されるコードは何ですか?私は、明示的にメモリを割り当てることなどは、ユーザーコンストラクタを呼び出す前に*行われなければならないことを意味します。 – Voo

+0

@mrkj:問題を調査したので、追加するものは何もありません。ちなみに詳細と実験的な確認のためにあなたの答えに+1してください。 – Gorpik