在一些非c++程序中使用c++代码时,c++运行时调用terminate()是否合法?

时间:2021-10-28 15:04:23

In certain cases - especially when an exception escapes a destructor during stack unwinding - C++ runtime calls terminate() which must do something reasonable post-mortem and then exit the program. When a question "why so harsh" arises the answer is usually "there's nothing more reasonable to do in such error situations". That sounds reasonable if the whole program is in C++.

在某些情况下——特别是当一个异常在堆栈展开时逃离一个析构函数时——c++运行时调用terminate(),它必须做一些合理的事后分析,然后退出程序。当一个问题“为什么这么苛刻”出现时,答案通常是“在这种错误情况下,没有什么比这更合理的了”。如果整个程序使用c++,这听起来很合理。

Now what if the C++ code is in a library and the program that uses the library is not in C++? This happens quite often - for example I might have a native C++ COM component consumed by a .NET program. Once terminate() is called inside the component code the .NET program suddenly ends abnormally. The program author will first of all think "I don't care of C++, why the hell is this library make my program exit?"

现在,如果c++代码在库中,而使用库的程序不在c++中,该怎么办?这经常发生——例如,我可能有一个由。net程序所消耗的本地c++ COM组件。一旦终止()在组件代码中调用,. net程序就会突然终止异常。程序作者首先会认为“我不关心c++,为什么这个库会让我的程序退出?”

How do I handle the latter scenario when developing libraries in C++? Is it reasonable that terminate() unexpectedly ends the program? Is there a better way to handle such situations?

在使用c++开发库时,我如何处理后一种情况?terminate()意外终止程序是否合理?有更好的方法来处理这种情况吗?

4 个解决方案

#1


11  

Why is the C++ runtime calling terminate()? It doesn't do it at random, or due to circumstances which cannot be defined and/or avoided when the code is written. It does it because your code does something that is defined to result in a call to terminate(), such as throwing an exception from a destructor during stack unwinding.

为什么c++运行时调用terminate()?它不会随机执行,或者由于编写代码时无法定义和/或避免的情况。它之所以这样做,是因为您的代码所做的事情被定义为导致调用terminate(),例如在堆栈展开期间从析构函数抛出异常。

There is a list in the C++ standard of all the situations which are defined to result in call to terminate(). If you don't want terminate() to be called, don't do any of those things in your code. The same applies to unexpected(), abort(), and so on.

在c++标准中有一个列表,列出了所有定义为调用terminate()的情况。如果不希望调用terminate(),那么不要在代码中执行这些操作。这同样适用于unexpected()、abort()等。

I don't think this is any different really from the fact that you have to avoid undefined behavior, or in general avoid writing code which is wrong. You also have to avoid behavior which is defined but undesirable.

我不认为这与你必须避免未定义的行为,或者通常避免编写错误的代码有什么不同。你还必须避免被定义但不受欢迎的行为。

Perhaps you have a particular example where it is difficult to avoid a call to terminate(), but throwing an exception from a destructor during stack unwinding isn't it. Just don't throw exceptions out of destructors, ever. This means designing your destructors such that if they do something which might fail, the destructor catches the exception and your code continues in a defined state.

也许您有一个特殊的示例,它很难避免调用terminate(),但是在堆栈展开期间从析构函数抛出异常不是吗?永远不要从析构函数中抛出异常。这意味着要设计析构函数,以便如果它们做了可能会失败的事情,析构函数会捕获异常,而您的代码将继续处于定义状态。

There are some situations where your system will impolitely hack your process away at the knees because of something that your C++ code does (although not by calling terminate()). For example, if the system is overcommitting memory and the VMM can't honour the promises malloc/new have made, then your process might be killed. But that's a system feature, and probably applies equally to the other language that's calling your C++. I don't think there's anything you can (or need to) do about it, as long as your caller is aware that your library might allocate memory. In that circumstance it's not your code's fault the process died, it's the defined response of the operating system to low-memory conditions.

有些情况下,由于c++代码所做的某些事情(尽管不是通过调用terminate()),系统会不礼貌地破坏进程。例如,如果系统过度提交内存,而VMM不能兑现malloc/new所做的承诺,那么您的进程可能会被杀死。但这是一个系统特性,它可能同样适用于调用c++的其他语言。我认为,只要调用者意识到库可能分配内存,就没有什么可以(或需要)做的事情。在这种情况下,不是代码的错误导致进程死亡,而是操作系统对低内存条件的定义响应。

#2


6  

I think the more fundamental issue isn't specifically what terminate does, but the library's design. The library may be designed to be used only with C++ in which case exceptions can be caught and handled as appropriate within the app.

我认为更根本的问题不是terminate它做什么,而是该库的设计。库的设计可能只适用于c++,在这种情况下,可以在应用程序中捕获和处理异常。

If the library is intended to be used in conjunction with non-C++ apps, it needs to provide an interface that ensures no exceptions leave the library, for example an interface that does a catch(...).

如果库打算与非c++应用程序一起使用,那么它需要提供一个接口,确保不会有异常离开库,例如一个执行catch(…)的接口。

#3


1  

Suppose you have a function in C++ called cppfunc and you are invoking it from another langugage (such as C or .NET). I suggest you create a wrapper function, let's say exportedfunc, like so:

假设您在c++中有一个名为cppfunc的函数,并且正在从另一个语言标记(如C或. net)调用它。我建议您创建一个包装函数,比方说exportedfunc,如下所示:

int exportedfunc(resultype* outresult, paramtype1 param1, /* ... */)
{
    try {
       *outresult = cppfunc(param1,param2,/* ... */);
       return 0; // indicate success
    }catch( ... ) {  // may want to have other handlers
       /* possibly set other error status info */
       return -1; // indicate failure
    }
}   

Basically, you need to ensure that exceptions do not cross language boundaries... so you need to wrap your C++ functions with a function that catches all exceptions and reports a status code or does something acceptable other than invoking std::terminate.

基本上,您需要确保异常不会跨越语言边界……因此,您需要用一个函数来包装您的c++函数,该函数捕获所有异常,并报告一个状态代码,或者除了调用std::终止之外,还可以执行其他可接受的操作。

#4


0  

The default terminate handler will call abort. If you don't want this behavior, define your own terminate handler and set it using set_terminate.

默认的终止处理程序将调用abort。如果您不想要这种行为,请定义自己的terminate处理程序并使用set_terminate设置它。

#1


11  

Why is the C++ runtime calling terminate()? It doesn't do it at random, or due to circumstances which cannot be defined and/or avoided when the code is written. It does it because your code does something that is defined to result in a call to terminate(), such as throwing an exception from a destructor during stack unwinding.

为什么c++运行时调用terminate()?它不会随机执行,或者由于编写代码时无法定义和/或避免的情况。它之所以这样做,是因为您的代码所做的事情被定义为导致调用terminate(),例如在堆栈展开期间从析构函数抛出异常。

There is a list in the C++ standard of all the situations which are defined to result in call to terminate(). If you don't want terminate() to be called, don't do any of those things in your code. The same applies to unexpected(), abort(), and so on.

在c++标准中有一个列表,列出了所有定义为调用terminate()的情况。如果不希望调用terminate(),那么不要在代码中执行这些操作。这同样适用于unexpected()、abort()等。

I don't think this is any different really from the fact that you have to avoid undefined behavior, or in general avoid writing code which is wrong. You also have to avoid behavior which is defined but undesirable.

我不认为这与你必须避免未定义的行为,或者通常避免编写错误的代码有什么不同。你还必须避免被定义但不受欢迎的行为。

Perhaps you have a particular example where it is difficult to avoid a call to terminate(), but throwing an exception from a destructor during stack unwinding isn't it. Just don't throw exceptions out of destructors, ever. This means designing your destructors such that if they do something which might fail, the destructor catches the exception and your code continues in a defined state.

也许您有一个特殊的示例,它很难避免调用terminate(),但是在堆栈展开期间从析构函数抛出异常不是吗?永远不要从析构函数中抛出异常。这意味着要设计析构函数,以便如果它们做了可能会失败的事情,析构函数会捕获异常,而您的代码将继续处于定义状态。

There are some situations where your system will impolitely hack your process away at the knees because of something that your C++ code does (although not by calling terminate()). For example, if the system is overcommitting memory and the VMM can't honour the promises malloc/new have made, then your process might be killed. But that's a system feature, and probably applies equally to the other language that's calling your C++. I don't think there's anything you can (or need to) do about it, as long as your caller is aware that your library might allocate memory. In that circumstance it's not your code's fault the process died, it's the defined response of the operating system to low-memory conditions.

有些情况下,由于c++代码所做的某些事情(尽管不是通过调用terminate()),系统会不礼貌地破坏进程。例如,如果系统过度提交内存,而VMM不能兑现malloc/new所做的承诺,那么您的进程可能会被杀死。但这是一个系统特性,它可能同样适用于调用c++的其他语言。我认为,只要调用者意识到库可能分配内存,就没有什么可以(或需要)做的事情。在这种情况下,不是代码的错误导致进程死亡,而是操作系统对低内存条件的定义响应。

#2


6  

I think the more fundamental issue isn't specifically what terminate does, but the library's design. The library may be designed to be used only with C++ in which case exceptions can be caught and handled as appropriate within the app.

我认为更根本的问题不是terminate它做什么,而是该库的设计。库的设计可能只适用于c++,在这种情况下,可以在应用程序中捕获和处理异常。

If the library is intended to be used in conjunction with non-C++ apps, it needs to provide an interface that ensures no exceptions leave the library, for example an interface that does a catch(...).

如果库打算与非c++应用程序一起使用,那么它需要提供一个接口,确保不会有异常离开库,例如一个执行catch(…)的接口。

#3


1  

Suppose you have a function in C++ called cppfunc and you are invoking it from another langugage (such as C or .NET). I suggest you create a wrapper function, let's say exportedfunc, like so:

假设您在c++中有一个名为cppfunc的函数,并且正在从另一个语言标记(如C或. net)调用它。我建议您创建一个包装函数,比方说exportedfunc,如下所示:

int exportedfunc(resultype* outresult, paramtype1 param1, /* ... */)
{
    try {
       *outresult = cppfunc(param1,param2,/* ... */);
       return 0; // indicate success
    }catch( ... ) {  // may want to have other handlers
       /* possibly set other error status info */
       return -1; // indicate failure
    }
}   

Basically, you need to ensure that exceptions do not cross language boundaries... so you need to wrap your C++ functions with a function that catches all exceptions and reports a status code or does something acceptable other than invoking std::terminate.

基本上,您需要确保异常不会跨越语言边界……因此,您需要用一个函数来包装您的c++函数,该函数捕获所有异常,并报告一个状态代码,或者除了调用std::终止之外,还可以执行其他可接受的操作。

#4


0  

The default terminate handler will call abort. If you don't want this behavior, define your own terminate handler and set it using set_terminate.

默认的终止处理程序将调用abort。如果您不想要这种行为,请定义自己的terminate处理程序并使用set_terminate设置它。