草庐IT

C++,__try 和 try/catch/finally

coder 2023-05-02 原文

我想知道关于 C++ 的 try/catch/finally block 。我见过这些带有两个下划线的命令,比如 __try。但是 MVSC 2010 项目也可以在没有下划线的情况下运行。那么什么时候需要这些下划线呢?

最佳答案

在 Windows 上,操作系统级别支持异常。它们被称为结构化异常处理 (SEH),大致相当于 Unix 信号。为 Windows 生成代码的编译器通常利用这一点,他们使用 SEH 基础结构来实现 C++ 异常。

根据 C++ 标准,throwcatch 关键字只抛出和捕获 C++ 异常。 MSVC 编译器对应的 SEH 异常代码为 0xe06d7363。最后 3 个字节是“msc”的 ASCII 码。

将它与操作系统支持统一还意味着在堆栈展开期间将调用 C++ 析构函数以处理 SEH 异常。执行展开的代码位于 Windows 内部,并以与任何 SEH 完全相同的方式处理由 throw 引发的 SEH。但是,Microsoft 编译器进行了优化,试图避免生成确保在所有情况下都调用析构函数所需的代码。如果它可以证明在控制对象生命周期的范围 block 内没有 throw 语句,那么它会跳过注册代码。这与异步 SEH 异常不兼容,如果您打算捕获 SEH 异常,则应使用/EHa 编译选项来抑制此优化。

有很多 SEH 异常类型。操作系统可以生成的在 ntstatus.h SDK 头文件中列出。此外,您可能会与使用 SEH 实现自己的异常处理的代码进行互操作,它们将使用自己的异常代码。与 .NET 一样,托管异常使用 0xe0434f4d(“com”)异常代码。

要在 C++ 程序中捕获 SEH 异常,您必须使用非标准的 __try 关键字。 __except 关键字类似于 C++ catch 关键字。它具有更多功能,您可以指定一个异常过滤器表达式来确定是否应捕获事件异常。一切皆有可能,但您通常只查看传递的异常信息以查看您是否有兴趣处理它。 __finally 关键字允许您编写在处理异常后运行的代码。在 C++ 中没有等价物,但在其他语言中并不少见。

正如评论中指出的那样,所有这些都没有得到很好的记录。证据就在布丁里。这是您可以使用的示例程序。它演示了 SEH 异常如何仍然允许调用 C++ 析构函数,前提是您使用/EHa 进行编译,以及如何在 SEH 之上实现 C++ 异常。需要 MSVC 编译器,使用 Ctrl+F5 运行以避免调试器有帮助:

#include "stdafx.h"
#include <windows.h>
#include <iostream>

// NOTE: the value of the C/C++, Code Generation, Enable C++ Exceptions setting in important
// Try it both with /EHsc (the default) and /EHa to see the difference

class Example {  
public:
    ~Example() { std::cout << "destructed" << std::endl; }
};

int filterException(int code, PEXCEPTION_POINTERS ex) {
    std::cout << "Filtering " << std::hex << code << std::endl;
    return EXCEPTION_EXECUTE_HANDLER;
}

void testProcessorFault() {
    Example e;
    int* p = 0;
    *p = 42;
}

void testCppException() {
    Example e;
    throw 42;
}

int main()
{
    __try {
        testProcessorFault();
    }
    __except(filterException(GetExceptionCode(), GetExceptionInformation())) {
        std::cout << "caught" << std::endl;
    }
    __try {
        testCppException();
    }
    __except(filterException(GetExceptionCode(), GetExceptionInformation())) {
        std::cout << "caught" << std::endl;
    }
    return 0;
}

输出:

Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught

关于C++,__try 和 try/catch/finally,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7049502/

有关C++,__try 和 try/catch/finally的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  3. ruby-on-rails - 更好的替代方法 try( :output). try( :data). try( :name)? - 2

    “输出”是一个序列化的OpenStruct。定义标题try(:output).try(:data).try(:title)结束什么会更好?:) 最佳答案 或者只是这样:deftitleoutput.data.titlerescuenilend 关于ruby-on-rails-更好的替代方法try(:output).try(:data).try(:name)?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. ruby - 在 ruby​​ 中使用 .try 函数和 .map 函数 - 2

    我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法

  7. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  8. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  9. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  10. ruby catch 和效率 - 2

    catch在Ruby中是为了跳出深度嵌套的代码。在Java中,例如Java用于处理异常的try-catch可以实现同样的效果,但它被认为是糟糕的解决方案,而且效率也很低。在用于处理异常的Ruby中,我们有begin-raise-rescue,我认为将它用于其他任务也很昂贵。Ruby的catch-throw真的是比begin-raise-rescue更有效的解决方案吗?或者还有其他原因可以使用它来打破嵌套block而不是begin-raise-rescue? 最佳答案 除了是摆脱控制结构的“正确”方式之外,catch-throw也明显

随机推荐