Почему программа не может получить правильную инструкцию возврата после разматывания стека? - PullRequest
1 голос
/ 02 мая 2020

Компилятор: g ++ 9.2.0 Операционная система: Windows 10 g ++ call:

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

Я запускаю основной поток с новый поток (th) и дождитесь его, внутри th запускается другой поток , в который будет выдано исключение. Таким образом, когда он появляется, начинается разматывание стека (от Object :: GenerateException до Object :: DoSomeWork, поскольку больше нет вызовов, это стек Object :: GenerateException), и управление передается в try-catch объекта Object :: DoSomeWork, там же вызывает цепочку для метода try-catch, так как Object :: DoSomeWork "знает", что он был вызван из main.

Я не могу понять, почему он не может обработать исключение и передать его в try-catch main.

Ответы [ 2 ]

1 голос
/ 02 мая 2020

Почему программа не может получить правильную инструкцию возврата после разматывания стека c ++?

Поскольку ваш код создает несколько потоков, и вы не перехватываете исключение в потоке, который фактически выдает исключение. Исключения не будут распространяться по потокам, даже если вы вызовете join() функцию-член std::thread.

Попробуйте блоки определены как динамические c конструкции стека. Блок try отлавливает исключения, генерируемые кодом, динамически достижимым по вызову, из его содержимого.

Когда вы создаете новый поток, вы создаете совершенно новый стек, который совсем не является частью динамического * 1029. * контекст блока try, даже если вызов try pthread_create или конструкция присоединяемого std::thread() находится внутри try.

Чтобы перехватить исключение, возникающее в потоке X, вы должны иметь try- Предложение catch в потоке X (например, вокруг всего в функции потока, аналогично тому, что вы уже делаете в 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 голосов
/ 02 мая 2020

С эта std::thread ссылка :

... если она завершается выдачей исключения, вызывается std::terminate.

Если в потоке возникнет необработанное исключение, программа будет принудительно завершена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...