std::packaged_task: exception across threads

std::packaged_task is a facility of c++ asynchronous programming std::future.

std::packaged_task can make exception across threading work.

#include <future>
#include <iostream>
#include <thread>
#include <chrono>
#include <functional>
#include <complex>	// std::sqrt
#include <memory>
#include <mutex>

namespace across
{
	std::mutex print_mutex;

	class my_task_class
	{
	private:
		std::shared_ptr<std::packaged_task<double(int)>> __task;
		std::jthread __thrd;
		std::future<double> __future;
	public:
		my_task_class()
		{
		}
	public:
		virtual ~my_task_class()
		{
			__task = {};
		}
	public:
		void run(int value)
		{
			__task = std::make_shared<std::packaged_task<double(int)>>(
				std::bind(
					&across::my_task_class::my_task,
					this,
					std::placeholders::_1
				)
			);
			__future = __task->get_future();
			__thrd = std::jthread{
				std::move(* std::move(__task)),
				value
			};
			__task = {};
		}
	public:
		double get()
		{
			return __future.get();
		}
	protected:
		double my_task(int x)
		{
			if (x < 0)
				throw std::runtime_error{"Error: Negative Value!"};
			return std::sqrt(x);
		}
	};
}

int main()
{
	for (int i=-3; i<=3; ++i)
	{
		across::my_task_class task;
		try
		{
			task.run(i);
			double result = task.get();
			std::unique_lock<std::mutex> lock{across::print_mutex};
			std::cout << "Result: " << result << std::endl;
		}
		catch (const std::exception & e)
		{
			std::unique_lock<std::mutex> lock{across::print_mutex};
			std::cout << "c++ std::exception: " << e.what() << std::endl;
		}
	}
}

Mon Aug 11 11:21:51 PM UTC 2025