Ответ 1
Этот метод основан на том, что исключения должны быть реализованы поточно-безопасным способом, чтобы исключения могли использоваться в многопоточном приложении. Даже pre С++ - 11 компиляторы поддерживали потокобезопасные исключения до того, как потоки стали частью стандарта С++.
Каждый поток throw
/catch
исключений независимо от других потоков, используя хранилище, зависящее от потока, для хранения исключений. throw
без аргумента перерисовывает текущую исключение, хранящуюся в этом потоковом хранилище. Это хранилище для исключения используется для хранения функции с ее захваченными аргументами (с учетом состояния лямбда или любого другого вызываемого).
Недостатком этого метода является то, что выбрасывание исключения обычно связано с распределением памяти, поэтому оно добавляет накладные расходы на вызовы new
/delete
.
Другой способ реализовать это - использовать не переносимый, но широко поддерживаемый спецификатор хранилища __thread
. Это позволяет избежать накладных расходов на распределение динамической памяти:
void f(void(*p)()) { // The C-style function.
p();
}
__thread void(*function)();
template<class Function>
void adapter() {
(*reinterpret_cast<Function*>(function))();
}
template<typename F>
void invoke_f(F const& func) {
function = reinterpret_cast<void(*)()>(&func);
f(adapter<F const>);
}
int main(int ac, char**) {
invoke_f([ac]{ std::cout << ac << '\n'; });
}