Я пишу библиотеку, которую хотел бы быть переносимой. Таким образом, он не должен зависеть от расширений glibc или Microsoft или чего-либо еще, что не входит в стандарт. У меня есть хорошая иерархия классов, полученных из std :: exception, которые я использую для обработки ошибок в логике и вводе. Знание того, что в конкретный файл и номер строки генерируется исключение определенного типа, полезно, но знание того, как выполняется его выполнение, было бы потенциально гораздо более ценным, поэтому я искал способы получения трассировки стека.
Мне известно, что эти данные доступны при сборке с использованием glibc с использованием функций из execinfo.h (см. вопрос 76822 ) и через интерфейс StackWalk в реализации Microsoft C ++ (см. вопрос 126450 *). 1006 *), но я бы очень хотел избежать всего, что не переносимо.
Я думал о реализации этой функции сам в этой форме:
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 требуют дополнительной настройки и завершения при каждом вызове функции, или они каким-то образом обрабатываются во время компиляции? Или есть другие вопросы, которые я не рассматривал?