试图在命令行中使用vcvarsall.bat编译以下代码时,会抛出一个警告,说明代码中需要异常处理程序,但在使用/EHsc
之前不需要调用异常处理程序。
代码:
#include <iostream>
int main()
{
std::cout << "hello world" << std::endl;
return 0;
}
批处理文件:
@echo off
cl C:\Development\..\basicmath.cpp
警告:
C:\...\ostream(746): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
C:...\basicmath.cpp(10): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)' being compiled
ostream第746行(来自错误)的第743 - 754行是_TRY:
if (!_Ok) {
_State |= ios_base::badbit;
} else { // state okay, insert
_TRY_IO_BEGIN
if ((_Ostr.flags() & ios_base::adjustfield) != ios_base::left) {
for (; 0 < _Pad; --_Pad) { // pad on left
if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) {
_State |= ios_base::badbit; // insertion failed, quit
break;
}
}
}
将/EHsc添加到我的批处理文件中将允许它运行,但我想知道为什么会这样。为什么输出文件中的这段代码需要调用EHsc?
MSDOCS说,EHsc是为了防止内存泄漏,是什么导致泄漏,为什么他们需要一个外部程序来修复泄漏,而不是在同一个文件中修复它(这听起来可能很粗鲁,但它只是无知)?
编辑:谢谢你指出这是一个警告,而不是错误。
发布于 2021-04-23 23:36:08
简短答覆:
将/EHs
或/EHsc
添加到您的编译选项中,正如文献资料建议的那样。如果您需要在Unix机器上执行相同的代码,这是关于异常处理的最可移植的选项。
较长的答覆:
这个问题有两部分。第一个是为什么警告发生在iostream
中,第二个是警告意味着什么。
为什么在iostream
**?**中有例外
C++中流的默认行为是无例外的--任何故障都是通过设置内部故障位来表示的,可以通过eof()
、fail()
和bad()
函数访问。但是,可以通过在流上使用exceptions()
方法将此行为更改为在失败时抛出异常。您可以选择哪些失败位触发异常,但重点是代码必须按照标准在那里。该警告似乎只分析-它注意到一个可能的路径发生throw
并报告警告。
这个警告是什么意思?
来自Microsoft文档 (重点雷):
默认情况下(也就是说,如果没有指定
/EHsc
、/EHs
或/EHa
选项),编译器将在本机C++catch(...)
子句中支持SEH处理程序。然而,也生成只部分支持C++异常的代码。默认异常展开代码不会破坏由于异常而超出作用域的try块之外的自动C++对象。
问题是(由于某种原因) MSVC编译器默认生成程序集,这是错误的标准。当抛出异常时,堆栈展开将不会完成,这可能会导致内存泄漏和其他意外行为。
一个正确的C++代码示例,该代码在默认设置下存在内存泄漏:
void foo()
{
std::string str = "This is a very long string. It definitely doesn't use Small String Optimization and it must be allocated on the heap."
std::cout << str;
throw std::runtime_error{"Oh no, something went wrong"};
}
int main()
{
try
{
foo();
}
catch (std::exception&)
{
// str in foo() was possibly not released, because it wasn't deleted when exception was thrown!
}
}
所以最后的答案是:
/EHa
。/EHs
以确保与C++标准的兼容性和可移植性。/EH
设置为一种或另一种选择,否则在使用异常时将不得不处理奇怪的行为。发布于 2021-04-23 23:36:31
这是一个警告,所以您的当前程序编译良好。但是,在这样的项目中出现了一些问题:
#include <exception>
#include <iostream>
struct A{
A(int x):x(x) {
std::cout<<"Contructed A::"<<x<<'\n';
}
~A() {
std::cout<<"Destructed A::"<<x<<'\n';
}
private:
int x;
};
void foo() {
A a{2};
throw std::bad_exception{};
}
int main()
{
A a {1};
try {
foo();
} catch(const std::bad_exception& ex) {
std::cout<<ex.what()<<'\n';
}
return 0;
}
使用cl test.cpp
生成输出:
Contructed A::1
Contructed A::2
bad exception
Destructed A::1
在使用cl test.cpp /EHsc
时,产量:
Contructed A::1
Contructed A::2
Destructed A::2
bad exception
Destructed A::1
此行为由警告C4530的文档解释。
当未启用/EHsc选项时,抛出函数与捕获异常的函数之间的堆栈帧中的自动存储对象不会被破坏。只有在try或catch块中创建的自动存储对象才会被销毁,这会导致严重的资源泄漏和其他意外行为。
这就解释了为什么当程序没有用/EHsc
编译时,/EHsc
没有被破坏。
当然,
如果在可执行文件中不可能引发异常,则可以安全地忽略此警告。
所以,对于像这样的程序
#include <cstdio>
int main()
{
std::printf("hello world\n");
return 0;
}
cl.exe
悄悄地编译。
https://stackoverflow.com/questions/67237550
复制相似问题