Подтвердить что ты не робот

Как std:: runtime_error:: runtime_error (const std::string &) отвечает std:: exception требование throw()?

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

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

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

4b9b3361

Ответ 1

(Вот то же самое в минимальной тестовой папке.)


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

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

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


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

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

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

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

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

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

Ответ 2

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

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

runtime_errorlogic_error) необходимы только для принятия аргумента типа std::string const &. Им не требуется копировать его.

Используйте эти перегрузки на свой страх и риск. LLVM libС++ не обеспечивает хранения.

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

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

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

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


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

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

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

Если std::runtime_error::runtime_error( std::string const & ) throws 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 > или некоторые из них для дезинфекции копий после первого.