如何在主函数范围之外调用析构函数来正确终止 C++ 程序

huangapple go评论74阅读模式
英文:

How to properly terminate a C++ program with calls to destructors outside the scope of main

问题

当前的C++标准是否提供了任何工具可以在任何地方关闭程序(例如从函数内部,类似于exit()),但同时保留堆上分配的资源?

我知道exit()函数应该释放所有内存(或者不释放,Google给出了两种答案),但在我的情况下,需要运行析构函数来释放外部系统资源。

英文:

Do current C++ standards provide any tools to close a program from anywhere (e.g. from inside a function, like exit()), but respecting the resources set aside on the heap?

I know that the exit() function should free all memory (or not, Google gives both answers), but in my case it is necessary to run destructors that will free external system resources.

答案1

得分: 1

将主要逻辑包装在main函数中,并使用try语句,创建catch(terminateException e),在catch范围内不需要编写任何内容。程序将正确结束并递归调用所有对象的析构函数,如果你对每个malloc使用了free,或者对每个new使用了delete,那么就不会有内存泄漏。

英文:

Wrap the main logic in main with try and create catch(terminateException e), in the catch scope you don't have to write anything. the program will finish correctly and call d'tors of all objects recursively, and if you have free for every malloc or delete for every new, you should have no memory leak.

答案2

得分: 1

假设您有一些静态和动态存储期的实体,就像这样(简化的示例,只有一个翻译单元):

struct DriverStatic
{
    DriverStatic(int id): _id{id} {}
    ~DriverStatic() { std::cout << "DriverStatic stopping: " << _id << std::endl; }
    int _id;
};

static DriverStatic ds1{1}, ds2{2};

struct DriverDynamic
{
    DriverDynamic(int id): _id{id} {}
    ~DriverDynamic() { std::cout << "DriverDynamic stopping: " << _id << std::endl; }
    int _id;
};

DriverDynamic* dn1 = new DriverDynamic{1};
DriverDynamic* dn2 = new DriverDynamic{2};

您可以注册一个或多个退出处理程序和一个终止处理程序:

int main()
{
    const int atex_result = std::atexit([]() {
        std::cout << "atexit\n";
        delete dn1;
        delete dn2;
    });
    if (atex_result != 0) {
        std::cerr << "Registration failed\n";
        return EXIT_FAILURE;
    }
    std::set_terminate([](){
        std::cout << "Unhandled exception\n" << std::flush;
        delete dn1;
        delete dn2;
        // not sure how to force static objects destruction
        std::abort();
    });
    // throw std::runtime_error("abnormal exit");
    return 0;
}

这样,当调用std::exit()时,您将首先销毁具有动态存储期的驱动程序,然后以未指定的顺序销毁具有静态存储期的驱动程序。

在异常程序终止的情况下,例如未捕获的异常,您的terminate_handler将触发,并尝试清理动态存储。

演示

但是,我不确定如何确保在异常情况下正确清理静态对象。请注意,如果在驱动程序的析构函数中引发某些未定义行为,您的系统可能仍无法按您的意愿执行操作。

无论如何,如果您正在控制一些安全关键硬件,请不要仅依赖于您的程序能够停止移动元素。提供一个心跳机制,并在软件连接丢失时进行系统互锁。

英文:

Assuming you have some static and dynamic storage duration entities like this (simplified example with just one translation unit):

struct DriverStatic
{
    DriverStatic(int id): _id{id} {}
    ~DriverStatic() { std::cout &lt;&lt; &quot;DriverStatic stopping: &quot; &lt;&lt; _id &lt;&lt; std::endl; }
    int _id;
};

static DriverStatic ds1{1}, ds2{2};

struct DriverDynamic
{
    DriverDynamic(int id): _id{id} {}
    ~DriverDynamic() { std::cout &lt;&lt; &quot;DriverDynamic stopping: &quot; &lt;&lt; _id &lt;&lt; std::endl; }
    int _id;
};

DriverDynamic* dn1 = new DriverDynamic{1};
DriverDynamic* dn2 = new DriverDynamic{2};

You can register both (one or more) exit handler and (one) terminate handler:

int main()
{
    const int atex_result = std::atexit([]() {
        std::cout &lt;&lt; &quot;atexit\n&quot;;
        delete dn1;
        delete dn2;
    });
    if (atex_result != 0) {
        std::cerr &lt;&lt; &quot;Registration failed\n&quot;;
        return EXIT_FAILURE;
    }
    std::set_terminate([](){
        std::cout &lt;&lt; &quot;Unhandled exception\n&quot; &lt;&lt; std::flush;
        delete dn1;
        delete dn2;
        // not sure how to force static objects destruction
        std::abort();
    });
    // throw std::runtime_error(&quot;abnormal exit&quot;);
    return 0;
}

This way when std::exit() is called, you will first destroy your drivers with dynamic storage duration, and then drivers with static storage duration will be destroyed in unspecified order.

In case of abnormal program termination, like uncaught exception, your terminate_handler will fire and will attempt to clean the dynamic storage.

Demo

I am not sure however, how to ensure correct static objects cleanup in the abnormal situation. And be aware that your system might still fail to do what you want, if you invoke some undefined behaviour, like throwing from the destructors of your drivers.

In any case, if you are controlling some safety-critical hardware, don't rely solely on your program being able to stop moving elements. Provide a heartbeat mechanism, and interlock your system when the software connection is lost.

huangapple
  • 本文由 发表于 2023年7月27日 14:29:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76777025.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定