Обновление, 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
ship для принятия внутреннего буфера аргумента 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
s с сайта вызовов, вы должны следовать §18.8.1 / 2:
Каждый стандартный библиотечный класс T, производный от исключения класса, должен иметь общедоступный конструктор копирования и общедоступный оператор назначения копирования, который не завершается с исключением.
Это необходимо, поскольку при копировании из стека в хранилище исключений потока чувствительно к исключениям. §15.1 / 7:
Если механизм обработки исключений, после завершения вычисления выражения, которое должно быть выброшено, но до того, как исключение было перехвачено, вызывает функцию, которая завершается через исключение, вызывается std :: terminate (15.5.1).
Итак, вы должны использовать shared_ptr< std::string >
или что-то подобное для дезинфекции копий после первого.