Как 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 >
или некоторые такие, чтобы дезинфицировать копии после первого.