为什么这个代码捕获块不执行

Why does this code catch block not execute?

本文关键字:执行 代码 为什么      更新时间:2023-10-16

catch 处理程序未运行。但是为什么?

如果thread ttry块之前启动,则 catch 处理程序将运行。

如果 catch 块的类型

与抛出的类型不匹配,程序将退出,说明线程以未捕获的异常终止,这表明异常已处理,但 catch 块未运行。

#include <iostream>
#include <thread>
using namespace std;
void do_work() {}
int main() {
  std::cerr << "RUNNING" << std::endl;
  try {
    thread t(do_work);
    std::cerr << "THROWING" << std::endl;
    throw logic_error("something went wrong");
  } catch (logic_error e) {
    std::cerr << "GOTCHA" << std::endl;
  }
  return 0;
}

编译命令:

c++ -std=c++14 -pthread -pedantic -Wall -Wextra -O0 scratch.cpp -o scratch

你忘了加入线程:

try {
  thread t(do_work);
  t.join();                                    // <<< add this
  std::cerr << "THROWING" << std::endl;
  throw logic_error("something went wrong");
} catch (logic_error e) {
  std::cerr << "GOTCHA" << std::endl;
}

超出范围的可联接线程会导致调用terminate。因此,您需要在超出范围之前调用joindetach

C++11, 30.3.1.3 中,标准说线程析构函数

如果 joinable() 则终止 (),否则没有效果。[注意:在其析构函数中隐式分离或加入 joinable() 线程都可能导致仅在引发异常时才遇到难以调试的正确性(用于分离)或性能(用于连接)错误。因此,程序员必须确保析构函数永远不会在线程仍可连接时执行。—尾注]

因此,一旦调用线程析构函数,程序就会terminate,因为作用域结束并且永远不会执行catch逻辑。

如果您希望程序在线程范围之外捕获异常,但在线程仍可连接时抛出,则需要在线程本身的范围内捕获它,连接或分离线程并重新抛出已捕获的任何内容。

try 
{
  std::thread t(foo);
  try
  {
    std::cerr << "THROWING" << std::endl;
    throw std::logic_error("something went wrong");
  }
  catch (...) // catch everything
  {
    t.join(); // join thread
    throw; // rethrow
  }
  t.join();
}
catch (std::logic_error & e) 
{
  std::cerr << "GOTCHA: " << e.what() << std::endl;
}