首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >为什么iostream在使用vcvarsall.bat编译“Hello”时要求调用异常处理程序?

为什么iostream在使用vcvarsall.bat编译“Hello”时要求调用异常处理程序?
EN

Stack Overflow用户
提问于 2021-04-23 22:33:36
回答 2查看 366关注 0票数 0

试图在命令行中使用vcvarsall.bat编译以下代码时,会抛出一个警告,说明代码中需要异常处理程序,但在使用/EHsc之前不需要调用异常处理程序。

代码:

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>

int main()
{
    std::cout << "hello world" << std::endl;
    
    return 0;
}

批处理文件:

代码语言:javascript
代码运行次数:0
运行
复制
@echo off

cl C:\Development\..\basicmath.cpp

警告:

代码语言:javascript
代码运行次数:0
运行
复制
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:

代码语言:javascript
代码运行次数:0
运行
复制
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是为了防止内存泄漏,是什么导致泄漏,为什么他们需要一个外部程序来修复泄漏,而不是在同一个文件中修复它(这听起来可能很粗鲁,但它只是无知)?

编辑:谢谢你指出这是一个警告,而不是错误。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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++代码示例,该代码在默认设置下存在内存泄漏:

代码语言:javascript
代码运行次数:0
运行
复制
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
  • 如果不需要捕获SE,请选择/EHs以确保与C++标准的兼容性和可移植性。
  • 永远不要离开默认值,始终将/EH设置为一种或另一种选择,否则在使用异常时将不得不处理奇怪的行为。
票数 1
EN

Stack Overflow用户

发布于 2021-04-23 23:36:31

这是一个警告,所以您的当前程序编译良好。但是,在这样的项目中出现了一些问题:

代码语言:javascript
代码运行次数:0
运行
复制
#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生成输出:

代码语言:javascript
代码运行次数:0
运行
复制
Contructed A::1
Contructed A::2
bad exception
Destructed A::1

在使用cl test.cpp /EHsc时,产量:

代码语言:javascript
代码运行次数:0
运行
复制
Contructed A::1
Contructed A::2
Destructed A::2
bad exception
Destructed A::1

此行为由警告C4530的文档解释。

当未启用/EHsc选项时,抛出函数与捕获异常的函数之间的堆栈帧中的自动存储对象不会被破坏。只有在try或catch块中创建的自动存储对象才会被销毁,这会导致严重的资源泄漏和其他意外行为。

这就解释了为什么当程序没有用/EHsc编译时,/EHsc没有被破坏。

当然,

如果在可执行文件中不可能引发异常,则可以安全地忽略此警告。

所以,对于像这样的程序

代码语言:javascript
代码运行次数:0
运行
复制
#include <cstdio>

int main()
{
    std::printf("hello world\n");
    
    return 0;
}

cl.exe悄悄地编译。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67237550

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档