简体   繁体   English

RAII与例外

[英]RAII vs. exceptions

The more we use RAII in C++, the more we find ourselves with destructors that do non-trivial deallocation. 我们在C ++中使用RAII的次数越多,我们就越发现自己的析构函数会进行非平凡的释放。 Now, deallocation (finalization, however you want to call it) can fail, in which case exceptions are really the only way to let anybody upstairs know of our deallocation problem. 现在,解除分配(终结,但是你想要调用它)可能会失败,在这种情况下,异常实际上是让楼上的任何人知道我们的释放问题的唯一方法。 But then again, throwing-destructors are a bad idea because of the possibility of exceptions being thrown during stack unwinding. 但是再说一次,抛出析构函数是一个坏主意,因为在堆栈展开期间可能会抛出异常。 std::uncaught_exception() lets you know when that happens, but not much more, so aside from letting you log a message before termination there's not much you can do, unless you're willing to leave your program in an undefined state, where some stuff is deallocated/finalized and some not. std::uncaught_exception()让你知道什么时候发生,但不是更多,所以除了让你在终止之前记录一条消息之外没有太多可以做的,除非你愿意让你的程序处于未定义的状态,有些东西被解除分配/最终确定,有些则没有。

One approach is to have no-throw destructors. 一种方法是使用无抛出析构函数。 But in many cases that just hides a real error. 但在许多情况下,这只是隐藏了一个真正的错误。 Our destructor might, for example, be closing some RAII-managed DB connections as a result of some exception being thrown, and those DB connections might fail to close. 例如,我们的析构函数可能会因为抛出某些异常而关闭一些RAII管理的数据库连接,并且这些数据库连接可能无法关闭。 This doesn't necessarily mean we're ok with the program terminating at this point. 这并不一定意味着我们可以在此时终止程序。 On the other hand, logging and tracing these errors isn't really a solution for every case; 另一方面,记录和跟踪这些错误并不是每个案例的真正解决方案; otherwise we would have had no need for exceptions to begin with. 否则我们就不需要开始例外了。 With no-throw destructors we also find ourselves having to create "reset()" functions that are supposed to be called before destruction - but that just defeats the whole purpose of RAII. 使用无抛出析构函数,我们还发现自己必须创建应该在销毁之前调用的“reset()”函数 - 但这只会破坏RAII的整个目的。

Another approach is just to let the program terminate , as it's the most predictable thing you can do. 另一种方法是让程序终止 ,因为这是你可以做的最可预测的事情。

Some people suggest chaining exceptions, so that more than one error can be handled at a time. 有些人建议链接异常,以便一次可以处理多个错误。 But I honestly never actually seen that done in C++ and I've no idea how to implement such a thing. 但老实说,我从来没有真正看到用C ++完成的工作,我也不知道如何实现这样的东西。

So it's either RAII or exceptions. 所以它是RAII或例外。 Isn't it? 不是吗? I'm leaning toward no-throw destructors; 我倾向于无抛出的破坏者; mainly because it keeps things simple(r). 主要是因为它保持简单(r)。 But I really hope there's a better solution, because, as I said, the more we use RAII, the more we find ourselves using dtors that do non-trivial things. 但我真的希望有一个更好的解决方案,因为,正如我所说,我们使用RAII的次数越多,我们发现自己越多地使用执行非平凡事情的dtors。

Appendix 附录

I'm adding links to interesting on-topic articles and discussions I've found: 我正在添加链接到我发现的有趣的主题文章和讨论:

You SHOULD NOT throw an exception out of a destructor. 不应该从析构函数中抛出异常。

Note: Updated to refeclt changes in the standard: 注意:已更新以更新标准中的更改:

In C++03 在C ++ 03中
If an exception is already propagating then the application will terminate. 如果异常已经传播,则应用程序将终止。

In C++11 在C ++ 11中
If the destructor is noexcept (the default) then the application will terminate. 如果析构函数是noexcept (默认值),则应用程序将终止。

The Following is based on C++11 以下是基于C ++ 11

If an exception escapes a noexcept function it is implementation defined if the stack is even unwound. 如果异常转义了noexcept函数,那么如果堆栈甚至被展开,则它是实现定义的。

The Following is based on C++03 以下是基于C ++ 03

By terminate I mean stop immediately. 终止,我的意思是立即停止。 Stack unwinding stops. 堆栈展开停止。 No more destructors are called. 不再需要析构函数。 All bad stuff. 所有不好的东西。 See the discussion here. 请参阅此处的讨论。

throwing exceptions out of a destructor 从析构函数中抛出异常

I don't follow (as in disagree with) your logic that this causes the destructor to get more complicated. 我不遵循(如不同意)你的逻辑,这会导致析构函数变得更复杂。
With the correct usage of smart pointers this actually makes the destructor simpler as everything now becomes automatic. 通过正确使用智能指针,这实际上使析构函数更简单,因为现在所有内容都变为自动化。 Each class tides up its own little piece of the puzzle. 每个班级都会将自己的小部分拼凑出来。 No brain surgery or rocket science here. 这里没有脑部手术或火箭科学。 Another Big win for RAII. RAII的另一大胜利。

As for the possibility of std::uncaught_exception() I point you at Herb Sutters article about why it does not work 至于std :: uncaught_exception()的可能性,我指出Herb Sutters关于它为什么不起作用的文章

From the original question: 从原来的问题:

Now, deallocation (finalization, however you want to call it) can fail, in which case exceptions are really the only way to let anybody upstairs know of our deallocation problem 现在,解除分配(终结,但是你想要调用它)可能会失败,在这种情况下异常实际上是让楼上的任何人知道我们的释放问题的唯一方法

Failure to cleanup a resource either indicates: 无法清理资源或者表明:

  1. Programmer error, in which case, you should log the failure, followed by notifying the user or terminating the application, depending on application scenario. 程序员错误,在这种情况下,您应该记录失败,然后通知用户或终止应用程序,具体取决于应用程序方案。 For example, freeing an allocation that has already been freed. 例如,释放已经释放的分配。

  2. Allocator bug or design flaw. 分配器错误或设计缺陷。 Consult the documentation. 请参阅文档。 Chances are the error is probably there to help diagnose programmer errors. 有可能是错误可能有助于诊断程序员错误。 See item 1 above. 见上文第1项。

  3. Otherwise unrecoverable adverse condition that can be continued. 否则不可恢复的不利条件可以继续。

For example, the C++ free store has a no-fail operator delete. 例如,C ++免费存储具有无失败运算符删除。 Other APIs (such as Win32) provide error codes, but will only fail due to programmer error or hardware fault, with errors indicating conditions like heap corruption, or double free, etc. 其他API(如Win32)提供错误代码,但只会因程序员错误或硬件故障而失败,错误指示堆损坏或双重释放等情况。

As for unrecoverable adverse conditions, take the DB connection. 至于不可恢复的不利条件,请采用DB连接。 If closing the connection failed because the connection was dropped -- cool, you're done. 如果关闭连接失败,因为连接被删除 - 很酷,你就完成了。 Don't throw! 不要扔! A dropped connection (should) result in a closed connection, so there's no need to do anything else. 断开的连接(应该)导致关闭连接,因此不需要做任何其他事情。 If anything, log a trace message to help diagnose usage issues. 如果有,请记录跟踪消息以帮助诊断使用问题。 Example: 例:

class DBCon{
public:
  DBCon() { 
    handle = fooOpenDBConnection();
  }
  ~DBCon() {
    int err = fooCloseDBConnection();
    if(err){
      if(err == E_fooConnectionDropped){
        // do nothing.  must have timed out
      } else if(fooIsCriticalError(err)){
        // critical errors aren't recoverable.  log, save 
        //  restart information, and die
        std::clog << "critical DB error: " << err << "\n";
        save_recovery_information();
        std::terminate();
      } else {
        // log, in case we need to gather this info in the future,
        //  but continue normally.
        std::clog << "non-critical DB error: " << err << "\n";
      }
    }
    // done!
  }
};

None of these conditions justify attempting a second kind of unwind. 这些条件都没有理由尝试第二种放松。 Either the program can continue normally (including exception unwind, if unwind is in progress), or it dies here and now. 程序可以正常继续(包括异常展开,如果正在进行展开),或者它在此处和现在都会消失。

Edit-Add 编辑-添加

If you really want to be able to keep some sort of link to those DB connections that can't close -- perhaps they failed to close due to intermittent conditions, and you'd like to retry later -- then you can always defer cleanup: 如果你真的希望能够保持与那些无法关闭的数据库连接的某种链接 - 也许它们由于间歇性条件而无法关闭,而你想稍后重试 - 那么你总是可以推迟清理:

vector<DBHandle> to_be_closed_later;  // startup reserves space

DBCon::~DBCon(){
  int err = fooCloseDBConnection();
  if(err){
    ..
    else if( fooIsRetryableError(err) ){
      try{
        to_be_closed.push_back(handle);
      } catch (const bad_alloc&){
        std::clog << "could not close connection, err " << err << "\n"
      }
    }
  }
}

Very not pretty, but it might get the job done for you. 非常不漂亮,但它可能会为你完成工作。

It reminds me a question from a colleague when I explained him the exception/RAII concepts: "Hey, what exception can I throw if the computer's switched off?" 当我向他解释异常/ RAII概念时,它让我想起了一位同事的问题:“嘿,如果计算机关闭,我可以抛出什么异常?”

Anyway, I agree with Martin York's answer RAII vs. exceptions 无论如何,我同意Martin York对RAII与异常的回答

What's the deal with Exceptions and Destructors? 与例外和破坏者有什么关系?

A lot of C++ features depend on non-throwing destructors. 许多C ++特性依赖于非抛出析构函数。

In fact, the whole concept of RAII and its cooperation with code branching (returns, throws, etc.) is based on the fact deallocation won't fail. 实际上,RAII的整个概念及其与代码分支(返回,抛出等)的合作是基于释放不会失败的事实。 In the same way some functions are not supposed to fail (like std::swap) when you want to offer high exception guarantees to your objects. 以同样的方式,当您想要为对象提供高异常保证时,某些函数不应该失败(如std :: swap)。

Not that it doesn't mean you can't throw exceptions through destructors. 并不是说它并不意味着你不能通过析构函数抛出异常。 Just that the language won't even try to support this behaviour. 只是语言甚至不会尝试支持这种行为。

What would happen if it was authorized? 如果它被授权会发生什么?

Just for the fun, I tried to imagine it... 只是为了好玩,我试着想象一下......

In the case your destructor fails to free your resource, what will you do? 如果你的析构函数无法释放你的资源,你会怎么做? Your object is probably half destructed, what would you do from an "outside" catch with that info? 你的物体可能已经被破坏了一半,你会从“外部”捕获的信息中做些什么呢? Try again? 再试一次? (if yes, then why not trying again from within the destructor?...) (如果是,那么为什么不在析构函数内再次尝试?...)

That is, if you could access your half-destructed object it anyway: What if your object is on the stack (which is the basic way RAII works)? 也就是说,如果你无论如何都可以访问你的半毁坏对象:如果你的对象在堆栈上(这是RAII工作的基本方式)怎么办? How can you access an object outside its scope? 如何访问其范围之外的对象?

Sending the resource inside the exception? 在异常中发送资源?

Your only hope would be to send the "handle" of the resource inside the exception and hoping code in the catch, well... try again to deallocate it (see above)? 你唯一的希望是在异常中发送资源的“句柄”并希望代码在catch中,好吧......再次尝试解除分配(参见上文)?

Now, imagine something funny: 现在,想象一下有趣的事:

 void doSomething()
 {
    try
    {
       MyResource A, B, C, D, E ;

       // do something with A, B, C, D and E

       // Now we quit the scope...
       // destruction of E, then D, then C, then B and then A
    }
    catch(const MyResourceException & e)
    {
       // Do something with the exception...
    }
 }

Now, let's imagine for some reason the destructor of D fails to deallocate the resource. 现在,让我们想象由于某种原因D的析构函数无法释放资源。 You coded it to send an exception, that will be caught by the catch. 你编写它来发送一个异常,它将被捕获。 Everything goes well: You can handle the failure the way you want (how you will in a constructive way still eludes me, but then, it is not the problem now). 一切顺利:你可以按照你想要的方式处理失败(你将如何以建设性的方式逃避我,但那时,现在不是问题)。

But... 但...

Sending the MULTIPLE resources inside the MULTIPLE exceptions? 在MULTIPLE异常中发送MULTIPLE资源?

Now, if ~D can fail, then ~C can, too. 现在,如果~D可能失败,那么~C也可以。 as well as ~B and ~A. 以及~B和~A。

With this simple example, you have 4 destructors which failed at the "same moment" (quitting the scope). 通过这个简单的例子,你有4个析构函数在“同一时刻”失败(退出范围)。 What you need is not not a catch with one exception, but a catch with an array of exceptions (let's hope the code generated for this does not... er... throw). 你需要的不是一个带有一个异常的catch,而是一个带有异常数组的catch(让我们希望为此生成的代码不会......呃...抛出)。

    catch(const std::vector<MyResourceException> & e)
    {
       // Do something with the vector of exceptions...
       // Let's hope if was not caused by an out-of-memory problem
    }

Let's get retarted ( I like this music... ): Each exception thrown is a different one ( because the cause is different: Remember that in C++, exceptions need not derive from std::exception ). 让我们重新启动( 我喜欢这个音乐... ):抛出的每个异常都是不同的( 因为原因不同:请记住,在C ++中,异常不需要从std :: exception派生 )。 Now, you need to simultaneously handle four exceptions. 现在,您需要同时处理四个异常。 How could you write catch clauses handling the four exceptions by their types, and by the order they were thrown? 你如何编写catch子句来处理它们的类型的四个异常,以及它们被抛出的顺序?

And what if you have multiple exceptions of the same type, thrown by multiple failed deallocation? 如果您有多个相同类型的异常,多次失败的重新分配会引发什么? And what if when allocating the memory of the exception arrays of arrays, your program goes out of memory and, er... throw an out of memory exception? 如果在分配数组的异常数组的内存时,你的程序内存不足,那么......抛出一个内存异常?

Are you sure you want to spend time on this kind of problem instead of spending it figuring why the deallocation failed or how to react to it in another way? 你确定你想花时间处理这类问题,而不是花时间去解决为什么解除分配失败或者如何以另一种方式对它做出反应?

Apprently, the C++ designers did not see a viable solution, and just cut their losses there. 显然,C ++设计人员没有看到可行的解决方案,只是减少了他们的损失。

The problem is not RAII vs Exceptions... 问题不在于RAII与例外......

No, the problem is that sometimes, things can fail so much that nothing can be done. 不,问题在于,有时候,事情可能会失败,以至于无法做任何事情。

RAII works well with Exceptions, as long as some conditions are met. 只要满足某些条件,RAII就可以很好地处理异常。 Among them: The destructors won't throw . 其中: 析构者不会抛出 What you are seeing as an opposition is just a corner case of a single pattern combining two "names": Exception and RAII 你所看到的反对意见只是一个结合两个“名称”的单一模式的极端情况:异常 RAII

In the case a problem happens in the destructor, we must accept defeat, and salvage what can be salvaged : "The DB connection failed to be deallocated? Sorry. Let's at least avoid this memory leak and close this File." 在析构函数中出现问题的情况下,我们必须接受失败,并挽救可以挽救的内容 :“数据库连接无法解除分配?抱歉。让我们至少避免此内存泄漏并关闭此文件。”

While the exception pattern is (supposed to be) the main error handling in C++, it is not the only one. 虽然异常模式(应该是)C ++中的主要错误处理,但它不是唯一的。 You should handle exceptional (pun intended) cases when C++ exceptions are not a solution, by using other error/log mechanisms. 通过使用其他错误/日志机制,当C ++异常不是解决方案时,您应该处理异常(双关语)案例。

Because you just met a wall in the language, a wall no other language that I know of or heard of went through correctly without bringing down the house (C# attempt was worthy one, while Java's one is still a joke that hurts me on the side... I won't even speak about scripting languages who will fail on the same problem in the same silent way). 因为你刚刚用语言碰到了一堵墙,所以没有其他语言,我知道或听说过的墙没有打倒房子而正确地进行了(C#尝试是值得的,而Java的一个仍然是一个让我受伤的笑话...我甚至不会谈论脚本语言,他们会以相同的静音方式在同一个问题上失败)。

But in the end, no matter how much code you'll write, you won't be protected by the user switching the computer off . 但最后,无论您编写多少代码,用户都不会受到用户保护

The best you can do, you already wrote it. 你已经写好了,你能做的最好。 My own preference goes with a throwing finalize method, a non-throwing destructor cleaning resources not finalized manually, and the log/messagebox (if possible) to alert about the failure in the destructor. 我自己的偏好是抛出finalize方法,非抛出析构函数清理未手动完成的资源,以及日志/消息框(如果可能)来警告析构函数中的失败。

Perhaps you're not putting up the right duel. 也许你没有进行正确的决斗。 Instead of "RAII vs. Exception", it should be " Trying to freeing resources vs. Resources that absolutely don't want to be freed, even when threatened by destruction " 而不是“RAII与异常”,它应该是“ 试图释放资源与资源,绝对不希望被释放,即使受到破坏的威胁

:-) :-)

You're looking at two things: 你正在看两件事:

  1. RAII, which guarantees that resources are cleaned up when scope is exited. RAII,保证在退出范围时清理资源。
  2. Completing an operation and finding out whether it succeeded or not. 完成操作并查明是否成功。

RAII promises that it will complete the operation (free memory, close the file having attempted to flush it, end a transaction having attempted to commit it). RAII承诺它将完成操作(空闲内存,关闭试图刷新它的文件,结束尝试提交它的事务)。 But because it happens automatically, without the programmer having to do anything, it doesn't tell the programmer whether those operations it "attempted" succeeded or not. 但是因为它是自动发生的,没有程序员必须做任何事情,它不会告诉程序员它“尝试”的操作是否成功。

Exceptions are one way to report that something failed, but as you say, there's a limitation of the C++ language that means they aren't suitable to do that from a destructor[*]. 异常是报告某些内容失败的一种方法,但正如您所说,C ++语言的局限性意味着它们不适合从析构函数[*]中执行此操作。 Return values are another way, but it's even more obvious that destructors can't use those either. 返回值是另一种方式,但更明显的是析构函数也不能使用它们。

So, if you want to know whether your data was written to disk, you can't use RAII for that. 因此,如果您想知道您的数据是否已写入磁盘,则无法使用RAII。 It does not "defeat the whole purpose of RAII", since RAII will still try to write it, and it will still release the resources associated with the file handle (DB transaction, whatever). 它并没有“打败RAII的整个目的”,因为RAII仍然会尝试编写它,它仍然会释放与文件句柄相关的资源(数据库事务,无论如何)。 It does limit what RAII can do -- it won't tell you whether the data was written or not, so for that you need a close() function that can return a value and/or throw an exception. 它确实限制了RAII可以执行的操作 - 它不会告诉您数据是否已写入,因此您需要一个close()函数,它可以返回值和/或抛出异常。

[*] It's quite a natural limitation too, present in other languages. [*]这也是一个很自然的限制,存在于其他语言中。 If you think RAII destructors should throw exceptions to say "something has gone wrong!", then something has to happen when there's already an exception in flight, that is "something else has gone wrong even before that!". 如果您认为RAII析构函数应该抛出异常说“出了问题!”,那么有些事情时,已经是在飞行中的例外,那就是发生“别的东西,甚至在此之前,已经错了!”。 Languages that I know that use exceptions don't permit two exceptions in flight at once - the language and syntax simply don't allow for it. 我知道使用异常的语言不允许同时出现两个例外 - 语言和语法根本不允许这样做。 If RAII is to do what you want, then exceptions themselves need to be redefined so that it makes sense for one thread to have more than one thing going wrong at a time, and for two exceptions to propagate outward and two handlers to be called, one to handle each. 如果RAII要做你想做的事情,那么异常本身需要重新定义,这样一个线程一次就会出现多个错误,并且有两个异常向外传播,两个处理程序被调用,一个人来处理每一个。

Other languages allow the second exception to obscure the first, for example if a finally block throws in Java. 其他语言允许第二个异常模糊第一个异常,例如,如果finally块抛出Java。 C++ pretty much says that the second one must be suppressed, otherwise terminate is called (suppressing both, in a sense). C ++几乎说必须抑制第二个,否则调用terminate (在某种意义上抑制两者)。 In neither case are the higher stack levels informed of both faults. 在这两种情况下都没有更高的堆栈级别通知两个故障。 What is a bit unfortunate is that in C++ you can't reliably tell whether one more exception is one too many ( uncaught_exception doesn't tell you that, it tells you something different), so you can't even throw in the case where there isn't already an exception in flight. 有点不幸的是,在C ++中,你无法可靠地判断是否还有一个例外太多( uncaught_exception没有告诉你,它告诉你一些不同的东西),所以你甚至无法抛出这样的情况:在飞行中还没有例外。 But even if you could do it in that case, you'd still be stuffed in the case where one more is one too many. 但即使你可以在这种情况下做到这一点,你仍然会被填充在一个太多的情况下。

One thing I would ask is, ignoring the question of termination and so on, what do you think an appropriate response is if your program can't close its DB connection, either due to normal destruction or exceptional destruction. 我要问的一件事是,忽略终止等问题,如果您的程序无法关闭其数据库连接,或者由于正常的破坏或异常破坏,您认为适当的响应是什么?

You seem to rule out "merely logging" and are disinclined to terminate, so what do you think is the best thing to do? 您似乎排除了“仅仅记录”并且不愿意终止,那么您认为最好的做法是什么?

I think if we had an answer to that question then we would have a better idea of how to proceed. 我想如果我们对这个问题有了答案,那么我们就会更好地了解如何继续。

No strategy seems particularly obvious to me; 没有任何策略对我来说特别明显; apart from anything else, I don't really know what it means for closing a database connection to throw. 除了其他任何东西,我真的不知道关闭数据库连接是什么意思。 What is the state of the connection if close() throws? 如果close()抛出,连接的状态是什么? Is it closed, still open, or indeterminate? 它是封闭的,仍然是开放的还是不确定的? And if it's indeterminate, is there any way for the program to revert to a known state? 如果它不确定,程序是否有任何方法可以恢复到已知状态?

A destructor failing means that there was no way to undo the creation of an object; 析构函数失败意味着无法撤消对象的创建; the only way to return the program to a known (safe) state is to tear down the entire process and start over. 将程序恢复到已知(安全)状态的唯一方法是拆除整个过程并重新开始。

What are the reasons why your destruction might fail? 你的破坏可能失败的原因是什么? Why not look to handling those before actually destructing? 为什么不在实际破坏之前处理那些?

For example, closing a database connection may be because: 例如,关闭数据库连接可能是因为:

  • Transaction in progress. 交易正在进行中。 (Check std::uncaught_exception() - if true, rollback, else commit - these are the most likely desired actions unless you have a policy that says otherwise, before actually closing the connection.) (检查std :: uncaught_exception() - 如果为true,则回滚,否则提交 - 这些是最可能需要的操作,除非您在实际关闭连接之前有其他说明的策略。)
  • Connection is dropped. 连接被删除。 (Detect and ignore. The server will rollback automatically.) (检测并忽略。服务器将自动回滚。)
  • Other DB error. 其他DB错误。 (Log it so we can investigate and possibly handle appropriately in the future. Which may be to detect and ignore. In the meantime, try rollback and disconnect again and ignore all errors.) (记录下来,以便我们可以调查,并可能在将来适当处理。可能是检测和忽略。同时,尝试回滚并再次断开连接并忽略所有错误。)

If I understand RAII properly (which I might not), the whole point is its scope. 如果我理解RAII(我可能不会),那么重点是它的范围。 So it's not like you WANT transactions lasting longer than the object anyway. 所以它不像你想要的交易持续时间长于对象。 It seems reasonable to me, then, that you want to ensure closure as best you can. 那么,对我来说,你想要尽可能确保关闭是合理的。 RAII doesn't make this unique - even without objects at all (say in C), you still would try to catch all error conditions and deal with them as best as you can (which is sometimes to ignore them). RAII没有使这个独特 - 即使没有任何对象(比如在C中),你仍然会尝试捕捉所有错误条件并尽可能地处理它们(有时候会忽略它们)。 All RAII does is force you to put all that code in a single place, no matter how many functions are using that resource type. 无论有多少函数使用该资源类型,所有RAII都会强制您将所有代码放在一个地方。

You can tell whether there is currently an exception in flight (eg we are between the throw and catch block performing stack unwinding, perhaps copying exception objects, or similar) by checking 您可以判断当前是否存在异常(例如,我们在throw和catch块之间执行堆栈展开,可能是复制异常对象,或者类似)通过检查

bool std::uncaught_exception()

If it returns true, throwing at this point will terminate the program, If not, it's safe to throw (or at least as safe as it ever is). 如果它返回true,则此时抛出将终止程序,如果不是,则抛出是安全的(或者至少与以前一样安全)。 This is discussed in Section 15.2 and 15.5.3 of ISO 14882 (C++ standard). 这在ISO 14882(C ++标准)的第15.2节和第15.5.3节中讨论。

This doesn't answer the question of what to do when you hit an error while cleaning up an exception, but there really aren't any good answers to that. 这并没有回答在清理异常时遇到错误时该怎么做的问题,但实际上没有任何好的答案。 But it does let you distinguish between normal exit and exceptional exit if you wait to do something different (like log&ignore it) in the latter case, rather than simply panicing. 但是如果你在后一种情况下等待做一些不同的事情(比如记录并忽略它),它确实可以让你区分正常退出和异常退出,而不是简单地捣蛋。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM