C++ 构造函数处不可访问的代码';s形闭合撑杆

C++ 构造函数处不可访问的代码';s形闭合撑杆,c++,visual-c++,constructor,visual-c++-2008,unreachable-code,C++,Visual C++,Constructor,Visual C++ 2008,Unreachable Code,我正在开发一个使用VC9构建的应用程序,突然发现了一个我不完全理解的警告:为什么在构造函数的右括号上有一个“无法访问的代码”警告? 再现问题的最小测试用例是: __declspec(noreturn) void foo() { // Do something, then terminate the program } struct A { A() { foo(); } // d:\foo.cpp(7) : warning C4702: unreachable code };

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

Edit:为了澄清,使用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
foo上的declspec(noreturn)正在生成此警告。您告诉编译器此函数不返回。因此,编译器发出警告,表示您的构造函数永远不会完成。

请参阅

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


右大括号可能会生成代码(如调用析构函数),但不会到达。

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

Gorpik走上了正确的轨道。我已经创建了两个类似的测试用例,对它们进行了编译和反汇编,我想我已经理解了其中的根本原因:构造函数总是隐式地生成一个返回语句,而这个返回语句由于noreturn函数而无法访问

noreturn\u构造函数.cpp

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
    foo();
  }
  ~A() {
  }
};
int main() {
  A a;
}
__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
  }
  ~A() {
    foo();
  }
};
int main() {
  A a;
}
noreturn\u析构函数.cpp

__declspec(noreturn) void foo() {
  // Do something, then terminate the program
}
struct A {
  A() {
    foo();
  }
  ~A() {
  }
};
int main() {
  A a;
}
__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
无法访问的代码是此隐式返回语句,它是在构造函数中生成的,而不是在析构函数中生成的:

-  000000000000000E: 48 8B 44 24 30     mov         rax,qword ptr [rsp+30h]
+  0000000000000005: 48 8B 44 24 08     mov         rax,qword ptr [rsp+8]

由于您在
foo()
中终止程序?将某个
私有化而不实现它是通常的方式,因此C++11必须
=delete
才能实现这一点。必须
foo()
\u declspec(noreturn)
?@ixe013:是,
foo()
在其他地方使用,我们必须在使用后标记无法访问的代码。我想我们可以有两个版本的
foo()
,但这感觉有点傻(一个只在构造函数中使用的特殊版本?)。因此,您有理由在构造函数期间禁用此警告,并用一条大注释解释原因。您能否更具体地说明在这种情况下无法访问生成的代码?问题是什么是不可触及的(而不是“什么是
\uu declspec(noreturn)
的意思”)。在这种情况下,不应该为析构函数生成代码;析构函数会做什么?为什么它会将析构函数的代码归因于构造函数的右括号?你是对的,解释太简单了。查看代码的反汇编,右括号为构造函数和析构函数生成完全相同的代码。因此,据我所知,警告必须在两种情况下生成(我不希望发生这种情况),或者不生成。顺便说一句,正常(或虚拟)方法也不会生成警告。我认为这是一个有趣的理论。除了用户指定的构造函数主体之外,生成了什么代码来构成“对象的实际构造”?在用户定义的构造函数之后运行什么代码?我的意思是,在调用用户构造函数之前,必须明确地分配内存等,那么还有什么呢?@mrkj:我知道你已经调查了这个问题,所以我没有什么要补充的+顺便说一句,关于细节和实验证实,我的回答可能太模糊了,但我不认为这抓住了我在答案中寻找的本质:为什么构造函数在终止之前调用noreturn函数会导致无法访问的代码警告,而在终止任何其他函数之前调用相同的noreturn函数不会导致无法访问的代码警告?