0

下面的代码使得析构函数被调用两次。

#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
}

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

在发布版本中,程序崩溃。在 Debug 上构建它,我的系统上是: 在此处输入图像描述

4

3 回答 3

4

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

你不能。该标准说无效的内存访问具有未定义的行为。没有“捕捉”UB 的标准方法。捕获和终止处理程序用于定义行为的异常。

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

于 2016-01-26T10:06:32.370 回答
1

“try/catch”这样的错误不会被捕获,因为在这种情况下崩溃的可能性很大。但是你可以尝试捕捉破坏的瞬间,使用信号和更男子气概的退出程序。移开视线:#include、signal()、sig_atomic_t ...

于 2016-01-26T11:05:08.020 回答
0

main首先,如您声明的注释void main中所述,标准仅允许第 3.6.1 节中的两种形式

  1. 实现不应预定义主要功能。该功能不得重载。它应该有一个声明的返回类型 int,否则它的类型是实现定义的。一个实现应允许两者

    (2.1) — () 返回 int 的函数和

    (2.2) — (int, pointer to point to char) 返回 int 的函数

其次,您正在重置您unique_ptr以管理一个临时对象,该临时对象在unique_ptr其范围结束时被销毁时将deleted 导致未定义的行为。您无法预测/捕获未定义行为导致的错误。

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

#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

于 2016-01-26T10:07:48.063 回答