当前位置:  开发笔记 > 编程语言 > 正文

如何知道导致异常的确切代码行?

如何解决《如何知道导致异常的确切代码行?》经验,为你挑选了3个好方法。

如果我自己生成异常,我可以在异常中包含任何信息:源文件的许多代码行和名称.像这样的东西:

throw std::exception("myFile.cpp:255");

但是未处理的异常或不是由我生成的异常是什么?



1> Frank Kruege..:

更好的解决方案是使用自定义类和宏.:-)

#include 
#include 
#include 
#include 

class my_exception : public std::runtime_error {
    std::string msg;
public:
    my_exception(const std::string &arg, const char *file, int line) :
    std::runtime_error(arg) {
        std::ostringstream o;
        o << file << ":" << line << ": " << arg;
        msg = o.str();
    }
    ~my_exception() throw() {}
    const char *what() const throw() {
        return msg.c_str();
    }
};
#define throw_line(arg) throw my_exception(arg, __FILE__, __LINE__);

void f() {
    throw_line("Oh no!");
}

int main() {
    try {
        f();
    }
    catch (const std::runtime_error &ex) {
        std::cout << ex.what() << std::endl;
    }
}


这仅在您使用自己的代码时才有效.哪个问题表明他们不是.
建议的做法是执行任何可能在what()函数中而不是构造函数中分配内存(例如字符串流操作)的操作.原因是在捕获点可能有更多可用资源(一旦堆栈已经解开),而不是在投掷点.
您可能希望使用`:std :: runtime_error(std :: string(file)+":"+ std :: to_string(line)+":"+ arg)`来避免ostream操作.

2> James Curran..:

似乎每个人都在尝试改进代码以在代码中抛出异常,并且没有人尝试您提出的实际问题.

这是因为它无法完成.如果抛出异常的代码仅以二进制形式呈现(例如,在LIB或DLL文件中),则行号消失,并且无法将对象连接到源代码中的行.


@Tuntable:它并非"意味着难".更好的方式是"它不是为舒适而建造的;它是为速度而建造的".
有没有办法在异常提出时打印下一条指令的地址?如果我们可以有指令地址,我们可以轻松获得代码行.

3> vividos..:

有几种可能性可以找出抛出异常的位置:

使用编译器宏

在throw位置使用__FILE____LINE__宏(如其他评论者已经显示的那样),或者在std例外中将它们用作文本,或者作为自定义异常的单独参数:

要么使用

throw std::runtime_error(msg " at " `__FILE__` ":" `__LINE__`);

或扔

class my_custom_exception {
  my_custom_exception(const char* msg, const char* file, unsigned int line)
...

请注意,即使在编译Unicode(在Visual Studio中)时,FILE也会扩展为单字节字符串.这适用于调试和发布.不幸的是,带有抛出异常代码的源文件名放在输出可执行文件中.

堆栈行走

通过遍历调用堆栈找出异常位置.

在使用gcc的Linux上,函数backtrace()和backtrace_symbols()可以获得有关当前调用堆栈的信息.请参阅gcc文档如何使用它们.必须使用-g编译代码,以便将调试符号放在可执行文件中.

在Windows上,您可以使用dbghelp库及其函数StackWalk64来遍历堆栈.有关详细信息,请参阅Jochen Kalmbach 关于CodeProject 的文章.这适用于调试和发布,您需要为所需的所有模块发送.pdb文件.

您甚至可以通过在抛出自定义异常时收集调用堆栈信息来组合这两种解决方案.调用堆栈可以存储在异常中,就像在.NET或Java中一样.请注意,在Win32上收集调用堆栈非常慢(我的最新测试显示每秒大约有6个收集的调用堆栈).如果您的代码抛出许多异常,这种方法会大大减慢您的程序.

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有