我不知道这通常不是所有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;
^~~~~~~~~~~
Du。我要什么好,让我们再试一次,这次正确了:
#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)如果这是正确的话,我想人们将不得不一遍又一遍地重新发明它;我的意思是这是一个如此简单的实用程序,必须在标准库中,对吗?因此,我想我要么错过了标准库中的东西,要么我正在做错事。
如何正确执行此操作?
答案 0 :(得分:6)
我听说建议使用C ++宏;
是的,但这并不意味着从不使用它们。目前,作为非宏解决方案,我们没有比__LINE__
更好的东西了,所以我真的看不到为此使用宏的问题。
如果这是正确的话,我想人们将不得不一遍又一遍地重新发明它。我的意思是,这是一个非常简单的实用程序,必须在标准库中,对吧?
它是:以assert
的形式。首先,std::logic_error
是一个非常糟糕的异常,因为逻辑错误是编程错误,通常无法由任何异常处理代码来处理。
在拥有断言时抛出std::logic_error
确实是一种糟糕的方式,因为某些代码可以捕获它,然后程序无提示地继续运行,这实际上不是断言的重点。
assert
是 not 不好的风格;实际上,我们在C ++ 20中获得了合同,在那里我们将有一个非宏assert
以及前置/后置条件。 :)进一步说明这一点:LLVM充满了assert
,到目前为止,它并不是一个糟糕的代码库。