Может ли std :: string :: compare (const char *) вызвать исключение? - PullRequest
11 голосов
/ 10 июля 2019

Это перегрузка (4) здесь

В разделе «Исключения» перегрузки 2,3,5,6 (которые имеют параметры pos1 и / или pos2) называются выбрасывающими std::out_of_range.

Перегрузка (4) не имеет параметров "pos", но она не отмечена noexcept.

Это зависит от реализации, кидает ли она или нет?

В libstdc ++ GCC 7 он вызывает char_traits<char>::length и char_traits<char>::compare. Кажется, что они не могут бросить, но не помечены noexcept.

1 Ответ

1 голос
/ 10 июля 2019

За исключением деструкторов, функций подкачки, конструкторов перемещения и операторов присваивания перемещения, стандарт помечает функцию noexcept, только если она имеет контракт шириной , т. Е. Она не имеет предпосылки. Эта перегрузка требует, чтобы аргумент был строкой с нулевым символом в конце, поэтому стандарт не помечает его как noexcept.

Рациональное указано в N3248 :

Функции, отмеченные noexcept, трудно проверить

Когда функция помечена noexcept, становится невозможным отмечать неудачные тесты, особенно в тестовых драйверах, бросая исключение. Типичным примером будет код который проверяет предварительные условия при входе в функцию:

T& std::vector<T>::front() noexcept {
 assert(!this->empty());
 return *this->data();
}

При проверке таких защитных проверок у тест-водителя разумным подходом является зарегистрировать обработчик assert, который генерирует четко определенное исключение, нарушенное предварительным условием, который ловит тестовый драйвер, чтобы убедиться, что соответствующие assert действительно место.

...

Теперь мы можем утверждать, что вызов функции вне контракта, когда vector пустое, неопределенное поведение, поэтому мы не должны ожидать никаких гарантий. Проблема в том, что неопределенное поведение задается библиотекой; компилятору этот код отлично определен и, если assert выдает исключение, программа должна завершиться хорошо определенным образом, подрывая тест-водителя.

Обратите внимание, что проблема здесь не в том, что мы используем утверждения для поиска ошибок в наших собственных реализации библиотеки, а скорее в пользовательском коде, который неправильно вызывает нашу библиотеку. Если мы удалим возможность проверить эти защитные утверждения, мы можем ошибиться, и тем самым подвергаем наших пользователей риску совершения гораздо более серьезных ошибок, чем распространение неожиданное исключение.


Кстати, из-за [res.on.exception.handling] / 5 :

Реализация может усилить спецификацию исключений для невиртуальной функции, добавив спецификацию исключений без выбрасывания.

... libstdc++ и libc++ могут пометить эту перегрузку noexcept.

...