如何捕获因无效内存块被销毁而导致的错误
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
中的两种形式
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
在其范围末尾被销毁时,该临时文件将是 delete
d,这会导致未定义的行为。您不能 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
}
"try/catch"这样的错误是不会catch的,因为这种情况下死机的概率很大。但是你可以尝试捕捉破坏的时刻,使用信号和更多的 menne 有尊严地退出程序。
移开视线:#include , signal(), sig_atomic_t ...
以下代码使析构函数被调用两次。
#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
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
在其范围末尾被销毁时,该临时文件将是 delete
d,这会导致未定义的行为。您不能 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
}
"try/catch"这样的错误是不会catch的,因为这种情况下死机的概率很大。但是你可以尝试捕捉破坏的时刻,使用信号和更多的 menne 有尊严地退出程序。 移开视线:#include , signal(), sig_atomic_t ...