Я не знаю, является ли это общей рекомендацией для всего кода C ++ в целом, но, по крайней мере, в некоторых контекстах рекомендуется не использовать макрос assert
и вместо этого генерировать исключения .
У меня всегда была проблема с этим подходом.Как узнать, какая строка вызвала исключение?
Ну, да, у нас есть константа препроцессора __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)
Этоправильный подход?Мои сомнения проистекают из того факта, что (а) я слышал, что макросы в C ++ рекомендуются против;(б) если бы это было правильно, я полагаю, что людям придется изобретать это снова и снова;Я имею в виду, что это такая простая утилита, которая должна быть в стандартной библиотеке, верно?Так что я либо что-то пропустил из стандартной библиотеки, либо «Doing Things Wrong ™», я полагаю.
Как это сделать правильно?