简体   繁体   English

构造函数的右大括号中无法访问的代码

[英]Unreachable code at constructor's closing brace

I'm working on an application built with VC9 and I've hit upon a warning I don't fully understand: why is there an "unreachable code" warning on the closing brace of the constructor? 我正在开发一个用VC9构建的应用程序,我遇到了一个我不完全理解的警告: 为什么在构造函数的右括号上有一个“无法访问的代码”警告?

The minimal testcase to reproduce the issue is: 重现问题的最小测试用例是:

__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;
}

This must be compiled with /W4 to trigger the warning. 必须使用/ W4编译才能触发警告。 Alternatively, you can compile with /we4702 to force an error on the detection of this warning. 或者,您可以使用/ 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

Can someone explain what, precisely, is unreachable here? 有人可以解释一下,究竟是什么在这里无法到达? My best theory is that it's the destructor, but I'd like a definitive answer. 我最好的理论是它是析构函数,但我想要一个确定的答案。

If I want to make this code warning-clean, how can I achieve that? 如果我想让这段代码警告清洁,我该如何实现呢? The best I can come up with is convert this to a compile-time error. 我能想到的最好的是将其转换为编译时错误。

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

Edit: for clarification, terminating the program with a noreturn function doesn't normally cause an unreachable code warning on the closing brace enclosing that function call. 编辑:为了澄清,使用noreturn函数终止程序通常不会在封闭该函数调用的右括号上导致无法访问的代码警告。

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

Results in: 结果是:

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

Gorpik is on the right track. Gorpik走在正确的轨道上。 I've created two similar test cases, compiled them, and disassembled them and I think I've come to understand the underlying reason: the constructor always generates a return statement implicitly and this return statement is unreachable due to the noreturn function. 我创建了两个类似的测试用例,编译它们并对它们进行反汇编,我想我已经理解了它的根本原因:构造函数总是隐式生成一个return语句,并且由于noreturn函数,这个return语句是无法访问的。

noreturn_constructor.cpp 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 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 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

The unreachable code is this implicit return statement, which is generated in the constructor but not the destructor: 无法访问的代码是这个隐式的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]

There are no destructors to be called at the end of A::A() , so that's not the problem. A::A()的末尾没有要调用的析构函数,所以这不是问题。 What cannot be reached is the actual construction of the object, which happens after the constructor has finished its execution. 无法达到的是对象的实际构造,它在构造函数完成执行后发生。 Since it can never finish, that compiler-generated code is unreachable. 由于它永远无法完成,因此编译器生成的代码无法访问。

The declspec(noreturn) on foo is producing this warning. foo上的declspec(noreturn)正在产生这个警告。 You're telling the compiler that this function does not return. 你告诉编译器这个函数没有返回。 So the compiler is emitting a warning that your constructor will never complete. 因此编译器会发出警告,指出构造函数永远不会完成。

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

"This __declspec attribute tells the compiler that a function does not return. As a consequence, the compiler knows that the code following a call to a __declspec(noreturn) function is unreachable." “这个__declspec属性告诉编译器函数没有返回。因此,编译器知道调用__declspec(noreturn)函数后的代码是无法访问的。”

The closing brace may generate code (like calling destructors), which will not be reached. 右括号可能会生成无法访问的代码(如调用析构函数)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM