我如何 try/catch 在 C++ 中创建对象?

How do I try/catch an object creation in C++?

我是 运行 我的程序 catchsegv 并且它在我的程序段错误之前显示 boost::archive::text_oarchive 析构函数 运行:

Backtrace:
??:?(_ZN5boost7archive28basic_streambuf_locale_saverIcSt11char_traitsIcEED1Ev)[0x50c678]
??:?(_ZN5boost7archive21basic_text_oprimitiveISoED1Ev)[0x50c833]
/usr/local/include/boost/archive/text_oarchive.hpp:97(_ZN5boost7archive18text_oarchive_implINS0_13text_oarchiveEED2Ev)[0x417baf]
/usr/local/include/boost/archive/text_oarchive.hpp:114(_ZN5boost7archive13text_oarchiveD2Ev)[0x416645]
...

我不确定为什么 boost::archive::text_oarchive 析构函数是 运行,据我所知该对象尚未完成。所以我的猜测是抛出了一个异常,这就是为什么析构函数是 运行..?

我有这个代码:

std::stringstream ss;
boost::archive::text_oarchive outArchive(ss);
outArchive << *instPtr;

catchsegv 输出显示 text_oarchive 析构函数在中间行被调用,我的程序从未到达第三行。

所以我想做的是将 outArchive 构造包装在 try/catch 块中。我试过这样:

boost::archive::text_oarchive outArchive;
try {
  boost::archive::text_oarchive outArchiveTemp(ss);
  outArchive = outArchiveTemp;
}
catch ( std::exception& ex ) {
  BOOST_LOG_TRIVIAL(info) << "Error creating text_oarchive...";
  exit( 1 );
}

但这不起作用,因为第一行没有 outArchive 的默认构造函数。恐怕我对 C++ 的理解不够好,无法做我想做的事情,这基本上是 try/catch 创建对象,以便诊断 outArchive 析构函数为什么是 运行 和我的代码段错误...有帮助吗?

相反,您可以创建一个指向 outarchive 的指针,并在 try 块中对其进行初始化(只是为了理解异常的原因。如果需要,将其分配给实际生产代码中的智能指针即使在您了解了异常的原因后仍继续使用指针。例如,如果您想这样做,请参阅 std::aut_ptr or std::unique_ptr)。

boost::archive::text_oarchive *outArchive;
try {
  outArchive = new boost::archive::text_oarchive(ss);
}
catch ( std::exception& ex ) {
  BOOST_LOG_TRIVIAL(error) << "Error creating text_oarchive..."<<ex;
  exit( 1 );
}

这一行没有意义:

The catchsegv output shows the text_oarchive destructor is called on the middle line, my program never reaches the third line.

不可能为这一行调用 text_oarchive 析构函数:

boost::archive::text_oarchive outArchive(ss);

所以,您可能被您正在使用的工具所愚弄,该工具 link 到此行 默认情况下没有任何其他行到 link 到。 发生这种情况是因为析构函数是隐式的,因此没有任何源代码行可以引用。

附带说明一下,您可以使用 c++filt 将工具的输出通过管道传输,以获取 C++ demangled 名称(更易于阅读),如下所示:

catchsigv [your args here] 2>&1 | c++filt

实际上,如果你有一个段错误,这意味着你的代码中的某个地方,内存访问是意外完成的(比如写入一个空指针或超出分配的区域等...)

当您发现错误时,要么为时已晚,要么没有。

例如对于越界访问,通常为时已晚,错误可能被分配器发现(new/delete/malloc/free/etc)之后 下一次调用分配器。

处理空指针(reading/writing/accessing)时通常不晚,立即发送段错误信号(SIGSEGV)。

在前一种情况下,您可以使用 Valgrind,它会在您完成越界访问时告诉您。

在后一种情况下,您应该 运行 您的程序在调试器下运行 (gdb/lldb/etc...),调试器将在发出信号的确切位置停止。检查周围的局部变量(和 this)是否使用了空值。

另请注意,分段错误 不会 try/catch 块捕获,因此尝试这样做没有意义, 不行。