Різниця між специфікатором C ++ 03 pick () C ++ 11 noexcept


100

Чи є якась різниця між throw()та noexceptіншими, ніж перевірка під час виконання та час компіляції відповідно?

Ця стаття Вікіпедії C ++ 11 говорить про те, що специфікатори метання C ++ 03 застарілі.
Чому так, чи noexceptдостатньо здатний покрити все, що знаходиться під час компіляції?

[Примітка. Я перевірив це питання та цю статтю , але не зміг визначити вагому причину депресії.]


7
Додавання до цієї приємної статті також noexceptможе призвести до перевірки часу виконання. Основна відмінність між ними полягає в тому, що розрив noexceptпричин std::terminateпри порушенні throwпричин std::unexpected. Також дещо інша поведінка розкручується у цих випадках.
Фіктик

Нічого "часу компіляції" не перевірено з деякими специфікаціями винятків, що "час виконання" перевірено в інших. Це лише міф, створений супротивниками специфікацій винятків C ++.
curiousguy

Відповіді:


129

Специфікатори винятків були застарілими, оскільки специфікатори винятків, як правило, жахлива ідея . noexceptбуло додано, тому що це єдино корисне використання специфікатора винятку: знати, коли функція не кине виняток. Таким чином, він стає двійковим вибором: функції, які будуть кидати, і функції, які не будуть кидати.

noexceptбуло додано, а не просто видалення всіх специфікаторів кидання, крім того, throw()що noexceptє більш потужним. noexceptможе мати параметр, який час компіляції перетворюється на булевий. Якщо булева правда, то noexceptпалички. Якщо булева помилка, то noexceptвона не прилипає і функція може кинутись.

Таким чином, ви можете зробити щось подібне:

struct<typename T>
{
  void CreateOtherClass() { T t{}; }
};

Є чи CreateOtherClassвиключення кидка? Це може бути, якщо Tконструктор за замовчуванням може. Як нам сказати? Подобається це:

struct<typename T>
{
  void CreateOtherClass() noexcept(is_nothrow_default_constructible<T>::value) { T t{}; }
};

Таким чином, CreateOtherClass()буде кидати iff, якщо цей конструктор за замовчуванням кидає. Це виправляє одну з головних проблем із специфікаторами винятків: їх нездатність розповсюджувати стек викликів.

Ви не можете цього зробити throw().


+1 Корисна відповідь, для мене все одно. Ще шукаю відповідь, яка говорить про те, чому я хотів би використати noexcept. Я ніколи не використовував throw()специфікатор, ніколи і намагаюся визначити, чи noexceptдійсно дає якусь користь (крім документації, перевіреної компілятором).
hmjd

Просто знайшов stackoverflow.com/questions/10787766 / ... ...
hmjd

1
@NicolBolas згоден. але якщо noexcept не буде гарантією, компілятор може перевірити, чи може функція перекидати деструктор чи ні. Таким чином, маючи можливість попередити програміста про те, що функція не є винятком чи ні.
Алекс

2
@NicolBolas виконує дзвінки std::terminate. що ВІДПОВІДНО ! код може прокрастися до релізів, які мають функції, позначені noexcept і під час виконання (тобто на сайтах клієнтів) виявляються порушення. Я мав на увазі, що компілятор гарантує генерування коду, який не викидає винятків в першу чергу.
Олексій

2
@NicolBolas: Ще одну різницю, яку варто зазначити. Якщо функція позначена, throws()то, якщо викинутий виняток, стек повинен бути розкручений до сфери дії цієї функції (тому всі автоматичні змінні функції знищуються), після чого terminate()викликається (через unexpected()). Якщо функція позначена, noexceptто якщо викинутий виняток, то викликається термінал (розмотування стека - деталізація, визначена реалізацією).
Мартін Йорк

33

noexcept не перевіряється під час компіляції.

Реалізація не повинна відкидати вираз лише тому, що при виконанні він викидає або може викинути виняток, який містить функція, яка не дозволяє.

Коли функція, яка оголошується noexceptабо throw()намагається викинути виняток, єдиною різницею є те, що один виклик terminateта інші дзвінки, unexpectedа останній стиль обробки винятків фактично застаріли.


Але якщо віртуальна функція має throw()/ noexcept, перевірка часу компіляції переконайтесь, що також існує і надмір.
curiousguy

2

std::unexpected() викликається під час виконання C ++, коли порушується специфікація динамічного виключення: викид викидається з функції, специфікація якої виключення забороняє винятки цього типу.

std::unexpected() може також бути викликаний безпосередньо з програми.

У будь-якому випадку std::unexpectedвиклику встановленого наразі std::unexpected_handler. std::unexpected_handlerДзвінки за замовчуванням std::terminate.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.