Скрытие longjmps в интерфейсе C ++ для кода C

Каков будет правильный способ создания API C ++ для старого кода C, который широко использует longjmp с несколькими целями перехода для управления ошибками?

Моя идея заключалась в том, чтобы написать функцию, которая устанавливает цели перехода для каждой используемой цели, например:

void catchJumps() {
if (setjmp(target1)) throw Error1(); //Error1 and Error2 are some exception classes
if (setjmp(target2)) throw Error2();
//...
}

Тогда я бы позвонил catchJumps в каждой C ++ — функции (в каждой области, если быть более точным), использующей код C:

int some_wrapper() {
catchJumps();
callCFunction()

for (int i = 0; i < 1000; i++) {
catchJumps();
callOtherCFunction();
}

catchJumps();
callOneMoreCFunction();
callEvenOneMoreCFunction();
}

Это безопасный способ поймать все longjumps, не разрушая стек? Я знаю, что longjmp опасно вставлять в другой фрейм стека. Теперь моя функция catchJumps находится в другом кадре стека, чем вызывающий some_wrapper, Я надеюсь (или я могу даже сделать это) catchJumps может быть встроен, так что кадр такой же, но я не знаю.

Вызов в каждой области видимости (и после цикла выше) должен быть необходим для вызова всех деструкторов объектов с областью видимости, верно?

Если это недопустимый метод для «преобразования» longjmps в утверждения для вызывающего приложения, что еще мы можем сделать?

5

Решение

У вас могут возникнуть проблемы при использовании catchJumps с автоматическими объектами, которые имеют деструкторы, как описано в https://stackoverflow.com/a/1376099/471164 и цитируя 18.7 / 4 «Другая поддержка времени выполнения»:

Если какие-либо автоматические объекты будут уничтожены брошенным исключением
передача управления другому (пункту назначения) в программе,
затем вызов longjmp (jbuf, val) в точке выброса, которая передает
управление той же (целевой) точкой имеет неопределенное поведение.

Я думаю, что лучший подход заключается в создании оболочки для каждой функции C, которую вы используете и которая может сделать longjmp переводя все эти нелокальные goto в исключения. Это также сделает ваш код чище, потому что у вас не будет catchJumps() повсюду, но только в этих функциях-оболочках.

3

Другие решения

Поскольку вы застряли с таким API в библиотеке, как насчет того, чтобы иметь catchJumps выполнить фактический вызов, требуя передачи вызываемого объекта с нулевым параметром и используя указатель функции или boost/std::function?

template <typename CallMe>
void catchJumps(CallMe wrappee)
{
if (setjmp(target1)) throw Error1(); //Error1 and Error2 are some exception classes
if (setjmp(target2)) throw Error2();
//...

wrappee();
}

int some_wrapper()
{
catchJumps(&callCFunction);

for (int i = 0; i < 1000; i++)
{
catchJumps(&callOtherCFunction);
}

catchJumps(&callOneMoreCFunction);
catchJumps(&callEvenOneMoreCFunction);
}
2

По вопросам рекламы [email protected]