Я пишу библиотеку, которая хотела бы быть переносной. Таким образом, он не должен зависеть от расширений glibc или Microsoft или чего-либо еще, что не соответствует стандарту. У меня хорошая иерархия классов, полученных из std:: exception, которые я использую для обработки ошибок в логике и вводе. Зная, что конкретный тип исключения был брошен в конкретный файл, и номер строки полезен, но знание того, как получившееся выполнение было потенциально намного более ценным, поэтому я рассматриваю способы получения трассировки стека.
Я знаю, что эти данные доступны при создании против glibc с использованием функций в execinfo.h(см. вопрос 76822) и через интерфейс StackWalk в реализации Microsoft С++ (см. вопрос 126450), но я очень хотел бы избежать всего, что не переносится.
Я думал о реализации этой функции в этой форме:
class myException : public std::exception
{
public:
...
void AddCall( std::string s )
{ m_vCallStack.push_back( s ); }
std::string ToStr() const
{
std::string l_sRet = "";
...
l_sRet += "Call stack:\n";
for( int i = 0; i < m_vCallStack.size(); i++ )
l_sRet += " " + m_vCallStack[i] + "\n";
...
return l_sRet;
}
private:
...
std::vector< std::string > m_vCallStack;
};
ret_type some_function( param_1, param_2, param_3 )
{
try
{
...
}
catch( myException e )
{
e.AddCall( "some_function( " + param_1 + ", " + param_2 + ", " + param_3 + " )" );
throw e;
}
}
int main( int argc, char * argv[] )
{
try
{
...
}
catch ( myException e )
{
std::cerr << "Caught exception: \n" << e.ToStr();
return 1;
}
return 0;
}
Это ужасная идея? Это означало бы большую работу, добавляющую блоки try/catch к каждой функции, но я могу жить с этим. Это не сработает, когда причиной исключения станет повреждение памяти или нехватка памяти, но в этом случае вы все равно ввернуты. Это может привести к вводящей в заблуждение информации, если некоторые функции в стеке не поймают исключения, добавят себя в список и реконструируют, но я могу хотя бы предоставить гарантию, что все мои библиотечные функции сделают это. В отличие от "реальной" трассировки стека я не получу номер строки в вызывающих функциях, но, по крайней мере, у меня было бы что-то.
Моя главная проблема - это возможность того, что это приведет к замедлению, даже если на самом деле нет исключений. Все ли эти блоки try/catch требуют дополнительной настройки и срыва при каждом вызове функции или как-то обрабатываются во время компиляции? Или есть другие проблемы, которые я не рассматривал?