如何将行号传递给异常?

gaa*_*kam 2 c++ exception line-numbers

我不知道这是否通常是所有C ++代码的通用建议,但是至少在某些情况下,建议不要使用assert宏,而是抛出异常

我一直对此方法有疑问。我怎么知道哪条线触发了异常?

好吧,是的,我们有__LINE__预处理器常量。但是,通过它并不容易。

我尝试的方法:

#include <stdexcept>

int main() {
  throw std::logic_error("__LINE__");
}
Run Code Online (Sandbox Code Playgroud)

 

terminate called after throwing an instance of 'std::logic_error'
  what():  __LINE__
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)

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

#include <stdexcept>

int main() {
  throw std::logic_error(__LINE__);
}
Run Code Online (Sandbox Code Playgroud)

 

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;
     ^~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

咄。我要什么 好的,让我们再试一次,这次正确了:

#include <stdexcept>
#include <sstream>

std::ostringstream lineno;

int main() {
  throw std::logic_error((lineno << __LINE__, lineno.str()));
}
Run Code Online (Sandbox Code Playgroud)

 

terminate called after throwing an instance of 'std::logic_error'
  what():  7
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)

最终这将起作用,但是,每当我想要在代码中拥有一个断言时,将所有这些复制粘贴都已经很乏味和烦人了。如果我也想包括文件名,那只会变得更糟。

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

#include <stdexcept>
#include <sstream>

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

int main() {
  fatal();
}
Run Code Online (Sandbox Code Playgroud)

 

terminate called after throwing an instance of 'std::logic_error'
  what():  6
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)

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

最后,我能带给我的最好的是:

#include <stdexcept>
#include <sstream>

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

int main() {
  FATAL;
}
Run Code Online (Sandbox Code Playgroud)

 

terminate called after throwing an instance of 'std::logic_error'
  what():  10
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)

这是正确的方法吗?我的怀疑来自于以下事实:(a)建议不要使用C ++中的宏;(b)如果这是正确的话,我想人们将不得不一遍又一遍地重新发明它;我的意思是这是一个非常简单的实用程序,必须在标准库中,对吗?因此,我想我错过了标准库中的某些东西,或者我正在做错事。

如何正确做到这一点?

Rak*_*111 6

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

是的,但这并不意味着从不使用它们。现在,我们没有比__LINE__非宏解决方案更好的任何东西了,所以我真的看不到为此使用宏的问题。

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

它是:的形式assert。首先,std::logic_error是一个非常糟糕的异常,因为逻辑错误是编程错误,通常不能由任何异常处理代码来处理。

std::logic_error有断言时抛出异常是很糟糕的样式,因为某些代码可以捕获它,然后程序无提示地继续运行,这实际上不是断言的重点。

assert不是不好的风格; 实际上,我们在C ++ 20中获得了合同,在该合同中,我们将具有非宏观assert条件和前提条件。:)进一步说明这一点:LLVM充满了asserts,到目前为止还算不错的代码库。