У меня есть функция (член класса), которую я хотел бы избежать сбоя приложения из-за неоднозначности. Для этого я добавил try catch bock, как показано ниже:
void getGene(unsigned int position){
T val;
try {
val = _genome.at(_isCircular ? position % _genome.size() : position);
}
catch (std::exception& e) {
std::cerr << "Error in [" << __PRETTY_FUNCTION__ << "]: "<< e.what() << std::endl;
exit(1);
}
return val;
}
Теперь я хочу добавить тестовый модуль Boost, который я подумал сделать что-то вроде
BOOST_AUTO_TEST_CASE(nonCircularGenome_test){
// set size to 10
test.setSize(10);
// set non circular
test.setNonCircular();
// gene at site # 12 does not exist in a 10-site long genome, must throw an exception
BOOST_CHECK_THROW(test.getGene(12), std::out_of_range);
Проблема в том, что я не могу заставить обе эти вещи работать. Блок try-catch хорошо работает в настройках релиза. Однако этот тест работает, только если я уберу блок try-catch и позволю функции вызвать исключение.
Каков наилучший способ заставить обе эти вещи работать так, чтобы пользователю было выдано правильное сообщение об ошибке на ходу, в то время как тесты явно проверяют отладку? Одним из способов является использование # ifdef / # endif DEBUG блоки, но я хочу избежать макросов препроцессора.
Заранее спасибо,
Нихилу
Похоже, вы неправильно понимаете объем и цель исключений — и, возможно, обработки ошибок в целом.
Прежде всего, вы должны определить, каковы предварительные условия вашей функции: делает getGene()
всегда ожидай position
быть действительным? Ожидает ли это, что его клиенты никогда предоставить неверные позиции?
В этом случае клиент, предоставивший недопустимую позицию (даже если клиент является процедурой тестирования), нарушает договор с getGene()
(в частности, это нарушает его предварительное условие), и нарушение контракта является неопределенным поведением по определению. Вы не можете проверить неопределенное поведение, поэтому вы должны удалить свой тест.
С другой стороны, если ваша функция имеет широкий контракт, то есть она позволяет клиентам передавать любой позиция (даже недействительная) и (a) выдает исключение или (b) возвращает код ошибки, чтобы сообщить об ошибке, когда позиция недействительна, тогда exit(1)
линия не должна быть там, потому что вы выходите из программы, и управление не передается обратно вызывающей стороне.
Одна возможность состоит в том, чтобы повторно выдать исключение после регистрации диагностики:
T getGene(unsigned int position){
T val;
try {
val = _genome.at(_isCircular ? position % _genome.size() : position);
}
catch (std::exception& e) {
std::cerr << "Error in [" << __PRETTY_FUNCTION__ << "]: "<< e.what() << std::endl;
throw;
// ^^^^^
}
return val;
}
И если вам не нужно печатать диагностику, просто позвольте распространению исключения:
T getGene(unsigned int position){
return _genome.at(_isCircular ? position % _genome.size() : position);
}
Других решений пока нет …