Ответ
std::exception_ptr — это тип из заголовка <exception>, представляющий обёртку с разделяемым владением (shared ownership) для захваченного исключения. Он позволяет сохранять и передавать исключения между контекстами, например, между потоками, для отложенной обработки.
Основное применение:
- Передача исключений из рабочего потока в главный (например, при использовании
std::async). - Создание цепочек или графов исключений.
- Реализация механизмов отложенного проброса.
Ключевые функции:
std::current_exception()— захватывает текущее активное исключение и возвращаетexception_ptrна него. Если исключения нет, возвращает пустойexception_ptr.std::rethrow_exception(exception_ptr p)— пробрасывает копию исключения, на которое указываетp.std::make_exception_ptr(E e)— создаётexception_ptrна копию исключенияe.
Пример передачи исключения между потоками:
#include <iostream>
#include <thread>
#include <exception>
#include <stdexcept>
void worker(std::exception_ptr& eptr) {
try {
// Имитация работы, которая может завершиться ошибкой
throw std::runtime_error("Ошибка в рабочем потоке");
} catch (...) {
eptr = std::current_exception(); // Захватываем исключение для передачи
}
}
int main() {
std::exception_ptr eptr;
std::thread t(worker, std::ref(eptr));
t.join();
// Обработка исключения из потока в главном потоке
if (eptr) {
try {
std::rethrow_exception(eptr);
} catch (const std::exception& e) {
std::cout << "Поймано исключение из потока: " << e.what() << 'n';
}
}
return 0;
}
Важно: exception_ptr безопасен для копирования и присваивания; ресурсы освобождаются автоматически, когда на исключение не остаётся ссылок.
Ответ 18+ 🔞
Слушай, вот объясню тебе про эту штуку std::exception_ptr, чтобы ты не охуел потом, когда она тебе на ровном месте вылезет. Представь себе, что исключение — это как горячая картошка: поймал в catch — и либо съел (обработал), либо сразу кинул дальше (throw). А что, если тебе надо эту гребаную картошку не сейчас есть, а, скажем, отложить в сторонку и передать другому чуваку, который в другом потоке сидит? Вот тут-то она и пригождается, эта обёрточка.
По сути, это такой умный указатель с разделяемым владением, как shared_ptr, только не на объект в куче, а на захваченное исключение. Засунул в него ошибку — и таскай себе куда хочешь, хоть через всю программу. Главное, потом не забыть вскрыть да посмотреть, что там внутри.
Зачем это, блядь, нужно?
Ну, например, ты запустил асинхронную хуйню через std::async, и она там в другом потоке благополучно обосралась. Как главный поток узнает про эту катастрофу? Вот именно — через exception_ptr. Рабочий поток ловит своё исключение, пакует его в эту обёртку и кидает тебе, как вызовом .get() от фьючерса. А ты уж в своём удобном контексте разворачиваешь и разбираешься, что за пиздец произошёл.
Основные инструменты в твои кривые руки:
std::current_exception()— это типа сачок. Внутри блокаcatch (...)вызываешь эту функцию, и она хватает текущее летящее исключение, какое бы оно ни было, и аккуратно кладёт в коробочкуexception_ptr. Если сачком махал впустую (не во время обработки исключения), вернёт пустую коробку.std::rethrow_exception(p)— команда "симона говорит". Передаёшь ей свойexception_ptr p, и она заново кидает копию того исключения, что внутри. Будь готов его снова ловить!std::make_exception_ptr(e)— для перфекционистов. Хочешь создатьexception_ptrпрямо из исключенияe, которое у тебя уже есть в руках? Вот тебе функция, без всяких тамtry/catch.
Смотри, как это выглядит в деле, на живом примере:
#include <iostream>
#include <thread>
#include <exception>
#include <stdexcept>
void worker(std::exception_ptr& eptr) {
try {
// Допустим, тут какая-то полезная работа, которая внезапно пошла по пизде
throw std::runtime_error("Ошибка в рабочем потоке");
} catch (...) {
// Хватаем этот летящий пиздец и суём в нашу обёртку для передачи
eptr = std::current_exception();
}
}
int main() {
std::exception_ptr eptr; // Пока тут пусто, терпения ебать ноль
std::thread t(worker, std::ref(eptr));
t.join();
// А вот теперь в главном потоке смотрим, не принёс ли нам worker говна в обёрточке
if (eptr) {
try {
std::rethrow_exception(eptr); // Распаковываем и кидаем
} catch (const std::exception& e) {
std::cout << "Поймано исключение из потока: " << e.what() << 'n';
}
}
return 0;
}
Важный момент на посошок: exception_ptr — не одноразовая штука. Его можно копировать, передавать, у него внутри счётчик ссылок. Когда последняя копия умрёт, память за исключением почистят. Удобно, ёпта. Не надо самому с этим ебаться.