Как отловить ошибку в результате уничтожения недопустимого блока памяти

Следующий код делает так, что деструктор вызывается дважды.

#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 построить его в моей системе:
введите описание изображения здесь

0

Решение

Как бы я поймал такую ​​ошибку в производстве?

Ты не можешь. Стандарт говорит, что недопустимый доступ к памяти имеет неопределенное поведение. Не существует стандартного способа «поймать» UB. Перехват и завершение обработчика для исключений, которые определенный поведение.

Что вы можете сделать, это использовать отладочную сборку в рабочей среде и запустить ее с помощью valgrind или аналогичного инструмента, чтобы вы могли хотя бы проанализировать ошибку.

4

Другие решения

«Попробуй / поймай» такие ошибки не поймаешь, потому что в этом случае велика вероятность крушения. Но момент разрушения вы можете попытаться поймать, используя сигналы более достойного выхода из программы.
Отводя взгляд: #include, signal (), sig_atomic_t …

1

Сначала, как отмечено в комментариях, которые вы объявляете main как void main где стандарт допускает только две формы в п. 3.6.1

  1. Реализация не должна предопределять основную функцию. Эта функция
    не должен быть перегружен. У него должен быть объявленный тип возвращаемого типа
    ИНТ
    , но в остальном его тип определяется реализацией.
    реализация должна позволять как

    (2.1) — функция (), возвращающая int и

    (2.2) — функция (int, указатель на указатель на символ), возвращающая int

Во-вторых, вы сбрасываете unique_ptr управлять временным, который, когда unique_ptr разрушается в конце своей области будет deleteг, что приводит к неопределенному поведению. Вы не можете предсказать / поймать ошибки, вызванные неопределенным поведением.

Что вы должны сделать (если вы действительно хотите использовать динамически распределенную память), вы можете вернуть указатель на объект в куче:

#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

0
По вопросам рекламы [email protected]