#опытным
В прошлом посте мы поговорили о том, что использование флага -fno-exceptions фактически трансформирует ваш код в диалект С++, в котором упоминание мира исключений карается ошибкой компиляции. Но каким образом компилируется код из стандартных заголовочных файлов? Там же повсюду обработка исключений?
Ответ прост. Макросы, товарищи. Вся магия в них. Вот на что заменяется обработка исключений:
#if __cpp_exceptions
# define __try try
# define __catch(X) catch(X)
# define __throw_exception_again throw
#else
# define __try if (true)
# define __catch(X) if (false)
# define __throw_exception_again
#endif
При запрете исключений, обработка заменяется на максимально безобидные инструкции, а проброс исключения дальше превращается в ничто.
Ну и для большинства классов, унаследованных от
exception, существуют соответствующие функции с C-линковкой:#if __cpp_exceptions
void __throw_bad_exception()
{ throw bad_exception(); }
#else
void __throw_bad_exception()
{ abort(); }
#endif
Тогда любая функция, которая бросает исключения должна триггерить std::abort. Или нет?
Нет. Вот примерчик.
Когда вы запрещаете исключения для своей программы, то это затрагивает только хэдэры стадартной либы. Но хэдэры определяют лишь интерфейс. Реализация std еще и неявно динамически линкуется к каждой программе. И по дефолту она собирается с использованием исключений.
Чтобы это исправить, можно собрать ее с запретом исключений. Примерно так:
git clone git://gcc.gnu.org/git/gcc.git
cd gcc
git checkout <target_release_tag>
./configure
--disable-libstdcxx-exceptions
CXXFLAGS="-fno-exceptions <all_flags_that_you_need>"
make -j$(nproc)
make install
Тогда у вас действительно всегда будет вызываться abort. Потому что все эти макросы также находятся в сорс файлах.
Extend your limits. Stay cool.
#compiler