为什么程序在堆栈释放后不能达到正确的返回指令?

问题描述 投票:0回答:1

编译器:g++ 9.2.0 操作系统。Windows 10 g++调用。

g++ -E main.cpp -v -o main.i
g++ -c main.cpp -v -o main.o 
g++ main.o -v -o main.exe
main.exe

main.cpp:

#include <chrono>
#include <iostream>
#include <string>
#include <exception>
#include <iostream>
//#include <thread>
#include "mingw.thread.h"
struct Object{
    struct Exception : public std::exception{
        std::string error_;
        Exception(std::string str){
            this->error_ = str;
        }
        ~Exception() {
        }
        std::string get(){
            return error_;
        }
    };
    void DoSomeWork() {
        try {
        std::thread AnotherTh(&Object::GenerateException ,this);
        AnotherTh.detach ();
        while(true);
    }
        catch (...) {
            throw ;
        }
    }
    void GenerateException(){
        std::this_thread::sleep_for (std::chrono::seconds(5));
        throw Object::Exception ("Some error");
    }
};
int main(){
    try{
        Object instance;
        std::thread th(&Object::DoSomeWork,std::ref(instance));
        th.join ();
    }
    catch (Object::Exception &ex ) {
        std::cout << ex.get ();
    }
    catch (std::exception &ex ){
        std::cout << ex.what ();
    }
    catch (...){
    }
    std::cout << "never reach this";
    return 0;
}

输出:我正在启动

terminate called after throwing an instance of 'Object::Exception'
  what():  std::exception

我正在启动 主线 附带 新线 等着吧,在里面 开始 另一线 异常将被抛出的地方。所以,当它出现时,开始堆栈解开(从Object::GenerateException到Object::DoSomeWork,因为Object::GenerateException的堆栈中没有更多的调用),并将管理传递给Object::DoSomeWork的try-catch,有相同的调用链到main的try-catch,因为Object::DoSomeWork "知道 "它是从main被调用的。

我不明白为什么它不能处理异常并将其传递给main的try-catch。

c++ exception stack g++ stack-unwinding
1个回答
1
投票

为什么c++程序在堆栈拆线后不能达到正确的返回指令?

因为你的代码创建了多个线程,而你没有在实际抛出异常的线程中捕获异常。异常不会在线程间传播,即使你调用了 join() 成员函数 std::thread.

尝试块 被定义为堆栈的动态结构。try块从它的内容中捕捉动态地、通过调用达到的代码所抛出的异常。

当你创建一个新的线程时,你创建了一个全新的堆栈,这个堆栈根本不属于 try 块的动态上下文,即使调用了 pthread_create 或构建可连接 std::thread() 是在try里面。

要捕获源自线程X的异常,必须在线程X中设置try-catch子句(例如,在线程函数中的所有内容周围,类似于在main中的做法)。

相关的问题,请看 如何在线程之间传播异常?.

一个例子。

#include <chrono>
#include <iostream>
#include <string>
#include <exception>
#include <iostream>
#include <thread>


struct Object {

    void DoSomeWork() 
    {
        std::cout << "DoSomeWork Thread ID: " << std::this_thread::get_id() << std::endl;
        try {
            std::thread thread(&Object::GenerateException, this);
            thread.detach();
            while(true);
        }
        catch (...) {
            std::cout << "Caught exception: " << std::this_thread::get_id() << std::endl;
            throw ;
        }
    }
    void GenerateException(void)
    {
        std::cout << "GenerateException Thread ID: " << std::this_thread::get_id() << std::endl;
        try {
            std::this_thread::sleep_for (std::chrono::seconds(5));
            throw std::runtime_error("Some error");
        } catch (...) {
            std::cout << "Caught exception: " << std::this_thread::get_id() << std::endl;
            throw;
        }
    }
};
int main()
{
    std::cout << "Main Thread ID: " << std::this_thread::get_id() << std::endl;
    try {
        Object instance;
        std::thread th(&Object::DoSomeWork,std::ref(instance));
        th.join();
    }
    catch (const std::exception &ex) {
        std::cout << ex.what() << std::endl;
        std::cout << "Exception caught at: " << std::this_thread::get_id() << std::endl;
    }
    std::cout << "never reach this" << std::endl;
    return 0;
}

输出:

Main Thread ID: 140596684195648
DoSomeWork Thread ID: 140596665124608
GenerateException Thread ID: 140596656670464
Caught exception: 140596656670464
terminate called after throwing an instance of 'std::runtime_error'
  what():  Some error
Aborted (core dumped)

0
投票

这个 std::thread 参考:

...如果它以抛出异常的方式终止。std::terminate 被调用。

如果在线程中抛出一个未捕获的异常,那么程序将被强制终止。

© www.soinside.com 2019 - 2024. All rights reserved.