如何捕获因无效内存块被销毁而导致的错误

How to catch an error resulting from an invalid memory block being destroyed

以下代码使析构函数被调用两次。

#include <iostream>
#include <memory>
#include <exception>
#include <cstdlib> 

void myterminate()
{
    std::cout << "terminate\n";
    abort();
}

class data 
{
    int a;
public:
    data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
    ~data() { std::cout << "dtor " << a << "\n"; }
    static data failure(int a) { return data(a); }
};

void main()
{
    std::set_terminate(myterminate); //terminate is not called
    try
    {
        std::unique_ptr<data> u;
        u.reset(&data::failure(1));
        std::cout << "no worries\n"; //this prints 
        //destructor called at try-block end and attempt to destruct an invalid memory block.
    }
    catch (...)
    {
        std::cout << "caught\n"; //this can not catch the error
    }
    std::cout << "end\n"; //program crash, will not be called
}

如何在生产中发现这样的错误?

在发布版本中,程序崩溃。在调试构建中,我的系统上是:

How would I catch an error like this in production?

你不能。该标准表示无效的内存访问具有未定义的行为。 "catch" UB 没有标准方法。捕获和终止处理程序用于异常,这是 定义的 行为。

您可以做的是在生产中使用调试版本,然后 运行 使用 valgrind 或类似工具,这样您至少可以分析错误。

首先,如注释中所述,您将 main 声明为 void main,其中标准仅允许 § 3.6.1

中的两种形式
  1. An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a declared return type of type int, but otherwise its type is implementation-defined. An implementation shall allow both

    (2.1) — a function of () returning int and

    (2.2) — a function of (int, pointer to pointer to char) returning int

其次,您正在重置 unique_ptr 以管理一个临时文件,当 unique_ptr 在其范围末尾被销毁时,该临时文件将是 deleted,这会导致未定义的行为。您不能 predict/catch 未定义行为导致的错误。

你应该做什么(如果你真的想使用动态分配的内存)你可以return一个指向堆上对象的指针:

#include <iostream>
#include <memory>
#include <exception>
#include <cstdlib> 

void myterminate()
{
    std::cout << "terminate\n";
    abort();
}

class data 
{
    int a;
public:
    data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
    ~data() { std::cout << "dtor " << a << "\n"; }
    static data* failure(int a) { return new data(a); }
};

int main()
{
    std::set_terminate(myterminate); //terminate is not called
    try
    {
        std::unique_ptr<data> u;
        u.reset(data::failure(1));
        std::cout << "no worries\n"; //this prints 
        //destructor called at try-block end and attempt to destruct an invalid memory block.
    }
    catch (...)
    {
        std::cout << "caught\n"; //this can not catch the error
    }
    std::cout << "end\n"; //program crash, will not be called
}

在线验证码:http://melpon.org/wandbox/permlink/pdiijgDxBshVOYRu

"try/catch"这样的错误是不会catch的,因为这种情况下死机的概率很大。但是你可以尝试捕捉破坏的时刻,使用信号和更多的 menne 有尊严地退出程序。 移开视线:#include , signal(), sig_atomic_t ...