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

Unreachable code at constructor's closing brace

本文关键字:访问 代码 构造函数      更新时间:2023-10-16

>我正在开发一个使用 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

> Gorpik 走在正确的轨道上。 我已经创建了两个类似的测试用例,编译了它们,并反汇编了它们,我想我已经理解了根本原因:构造函数总是隐式生成一个 return 语句,并且由于 noreturn 函数,这个 return 语句无法访问。

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]

A::A()末尾没有要调用的析构函数,所以这不是问题。无法到达的是对象的实际构造,这发生在构造函数完成其执行之后。由于它永远无法完成,因此无法访问编译器生成的代码。

foo 上的 declspec(noreturn) 正在产生此警告。 你告诉编译器此函数不会返回。 因此,编译器会发出构造函数永远不会完成的警告。

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

"这个__declspec属性告诉编译器函数不返回。因此,编译器知道调用 __declspec(noreturn) 函数后的代码无法访问。

右大括号可能会生成代码(如调用析构函数),这些代码将无法访问。