【问题标题】:How to pass a line number to an exception?如何将行号传递给异常?
【发布时间】:2019-05-19 17:27:14
【问题描述】:

我不知道这是否是所有 C++ 代码的普遍建议,但至少在某些情况下it is recommended to not use the assert macro and instead throw exceptions

我一直对这种方法有疑问。我怎么知道哪一行触发了异常?

嗯,是的,我们有 __LINE__ 预处理器常量。但是,通过它并非易事。

我尝试过的方法:

#include <stdexcept>

int main() {
  throw std::logic_error("__LINE__");
}

 

terminate called after throwing an instance of 'std::logic_error'
  what():  __LINE__
Aborted (core dumped)

嗯,这不是我想要的。让我们再试一次:

#include <stdexcept>

int main() {
  throw std::logic_error(__LINE__);
}

 

wtf.cc: In function ‘int main()’:
wtf.cc:4:34: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
   throw std::logic_error(__LINE__);
                                  ^
In file included from wtf.cc:1:0:
/usr/include/c++/7/stdexcept:124:5: note:   initializing argument 1 of ‘std::logic_error::logic_error(const char*)’
     logic_error(const char*) _GLIBCXX_TXN_SAFE;
     ^~~~~~~~~~~

呃。我想要什么?好的,让我们再试一次,这次是正确的:

#include <stdexcept>
#include <sstream>

std::ostringstream lineno;

int main() {
  throw std::logic_error((lineno << __LINE__, lineno.str()));
}

 

terminate called after throwing an instance of 'std::logic_error'
  what():  7
Aborted (core dumped)

这终于可行了,但是,每次我想在我的代码中有一个断言时复制粘贴所有这些已经是乏味和烦人的;如果我还想包含文件名,那只会变得更糟。

但是,删除代码重复的典型方法在这里显然会失败:

#include <stdexcept>
#include <sstream>

void fatal() {
  std::ostringstream slineno;
  slineno << __LINE__;
  std::string lineno = slineno.str();
  throw std::logic_error(lineno);
}

int main() {
  fatal();
}

 

terminate called after throwing an instance of 'std::logic_error'
  what():  6
Aborted (core dumped)

遗憾的是,不是这个精确的行号。

最后,我能做到的最好的:

#include <stdexcept>
#include <sstream>

#define FATAL {std::ostringstream slineno; \
               slineno << __LINE__; \
               std::string lineno = slineno.str(); \
               throw std::logic_error(lineno);}

int main() {
  FATAL;
}

 

terminate called after throwing an instance of 'std::logic_error'
  what():  10
Aborted (core dumped)

这是正确的方法吗?我的怀疑源于以下事实:(a)我听说 C++ 中的宏被推荐反对; (b) 如果这是正确的,我想人们将不得不一遍又一遍地重新发明它;我的意思是这是一个如此简单的实用程序,它必须在标准库中,对吧?所以要么我错过了标准库中的一些东西,要么我做错了™,我想。

如何正确地做到这一点?

【问题讨论】:

  • 链接问题中的方法似乎特定于 Rcpp

标签: c++ exception line-numbers


【解决方案1】:

我听说建议不要使用 C++ 中的宏;

是的,但这并不意味着从不使用它们。目前我们没有比 __LINE__ 更好的非宏解决方案,所以我真的不认为使用宏来解决这个问题。

如果这是正确的,我想人们将不得不一遍又一遍地重新发明它;我的意思是这是一个如此简单的实用程序,它必须在标准库中,对吧?

是:assert的形式。首先,std::logic_error 是一个非常糟糕的异常,因为逻辑错误是编程错误,一般来说任何异常处理代码都无法处理。

当你有一个断言时抛出 std::logic_error 真的很糟糕,因为一些代码可以捕捉到它,然后程序默默地继续,这并不是断言的真正意义。

assert不是不好的风格;事实上,我们在 C++20 中获得合同,我们将有一个非宏 assert 和前置/后置条件。 :) 进一步推动这一点:LLVM 充满了asserts,到目前为止,它并不是一个糟糕的代码库。

【讨论】:

    猜你喜欢
    • 2021-10-24
    • 2014-08-20
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多