Как std::runtime_error::runtime_error(const std::string&) может удовлетворить требование std:: исключения для throw()?

std::exception требует, чтобы его конструктор throw(), Еще std::runtime_error принимает std::string в качестве аргумента, который указывает, что он хранит std::string где-то. Следовательно, назначение или копирование должно происходить где-то. И для std::stringэто не nothrow операция.

Как тогда runtime_error::runtime_error встретить throw()?

(Для контекста я реализую тип исключения и хочу сохранить несколько std::stringс сайта вызова, и я хочу сделать это правильно...)

2 ответа

Решение

( Вот то же самое в минимальном тестовом сценарии.)


runtime_error::runtime_error(string const&) не нужно встречаться throw(),

Он не наследуется и не переопределяет exception::exception() и к тому времени string Копируется конструктор копирования, exception::exception() завершено.

Если копировать string были бы бросить исключение, это раскрутило бы runtime_error::runtime_error(string const&) а потом, я полагаю, вызвать exception::~exception(),


Трудно прямо показать, что не требуется, чтобы производный ctor соответствовал спецификатору исключений базового ctor, но это сильно подразумевается в следующем отрывке (в котором описывается, как вызывается деструктор base, а не передача исключения в конструктор base).):

[2003: 15.2/2] Объект, который частично создан или частично разрушен, будет иметь деструкторы, выполненные для всех его полностью построенных подобъектов, то есть для подобъектов, для которых конструктор завершил выполнение, а деструктор еще не начал выполнение. Если конструктор для элемента автоматического массива выдает исключение, будут уничтожены только созданные элементы этого массива. Если объект или массив был выделен в новом выражении, соответствующая функция освобождения (3.7.3.2, 5.3.4, 12.5), если таковая имеется, вызывается для освобождения памяти, занимаемой объектом.

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

[2003: 15.4/3] Если виртуальная функция имеет спецификацию исключений, все объявления, включая определение любой функции, которая переопределяет эту виртуальную функцию в любом производном классе, должны разрешать только те исключения, которые разрешены спецификацией исключений виртуальной функции базового класса.

Но ясно exception::exception() это не виртуальная функция, а четко runtime_error::runtime_error(string const&) не отменяет это.

(Обратите внимание, что этот сценарий будет применяться для виртуального деструктора; соответственно, вы можете видеть, что в libstdC++, runtime_error::~runtime_error() является throw()).

Обновление, 2015:

Еще std::runtime_error принимает std::string в качестве аргумента, который указывает, что он хранит std::string где-то. Следовательно, назначение или копирование должно происходить где-то. И для std::string это не noexcept операция.

runtime_error (а также logic_error) требуется только принять аргумент типа std::string const &, Они не обязаны копировать это.

Используйте эти перегрузки на свой страх и риск. LLVM libC++ не предоставляет хранилища.

С другой стороны, GNU libstdC++ осторожно на цыпочках, чтобы избежать нехватки памяти. Копирует содержимое строки, но в область хранения исключений, а не в новый std::string,

Даже тогда это добавляет std::string&& перегрузка и использование friend корабль принять внутренний буфер std::string аргумент, переданный rvalue, для экономии места хранения исключений.

Вот ваш реальный ответ: "Очень осторожно, если вообще".

Вы можете использовать щедрость GCC, используя std::runtime_error s как члены вашего собственного класса исключений, сохраняя одну строку каждый. Это все равно будет бесполезно на Clang, хотя.


Оригинальный ответ, 2011 год. Это все еще верно:

Исключение во время разматывания стека terminate быть названным.

Но создание объекта, который должен быть брошен, не является частью разматывания, и обрабатывается ничем не иначе, чем код до throw выражение.

Если std::runtime_error::runtime_error( std::string const & ) бросает std::bad_alloc, runtime_error исключение потеряно (оно никогда не существовало) и bad_alloc обрабатывается вместо

Демонстрация: http://ideone.com/QYPj3

Что касается хранения вашего собственного класса std::string С сайта вызова, вы хотите следовать §18.8.1/2:

Каждый стандартный библиотечный класс T, производный от исключения класса, должен иметь общедоступный конструктор копирования и общедоступный оператор присвоения копии, который не завершается с исключением.

Это необходимо, потому что копирование из стека в хранилище исключений потока чувствительно к исключениям. §15.1/7:

Если механизм обработки исключений, после завершения вычисления выражения, которое должно быть выброшено, но до того, как исключение было перехвачено, вызывает функцию, которая завершается через исключение, вызывается std::terminate (15.5.1).

Итак, вы должны использовать shared_ptr< std::string > или некоторые такие, чтобы дезинфицировать копии после первого.

Другие вопросы по тегам