Как использовать noexcept в C++ или как это работает?



Я не могу понять использование и назначение ключевого слова noexcept in в C++11/14. Я имею в виду, что это сигнатура для тех функций, которые не испускают exceptions. Но действительно ли это работает?



Посмотрите на этот код ниже:



#include <iostream>
#include <bits/stdc++.h>
using namespace std;
void seev (vector<int> &v) noexcept;
void seev (vector<int> &v) noexcept
{
for (int i=0;i<10;++i)
{
cout<<v.at(i)<<' ';
}
}
int main()
{
vector<int> v {1,2,3,4,5};
seev(v);
return 0;
}


Приведенный выше код наверняка бросит out_of_range exception. Так что использование noexcept здесь бесполезно, или это так?



Мои запросы:





  1. Как работает noexcept?



  2. Как это используется?



  3. Что throw() не смогло этого сделать noexcept мог бы?


1103   3  

3 ответов:

Спецификация noexcept для функции-это всего лишь метод, с помощью которого программист сообщает компилятору, должна ли функция создавать исключения.

Компилятор может использовать эту информацию для включения определенных оптимизаций для функций, не вызывающих метание, а также для включения оператора noexcept, который может проверять во время компиляции, объявляется ли конкретное выражение для создания каких-либо исключений.

Например, контейнеры типа std:: vector будут перемещать свои элементы, если элементы' конструктор перемещения-noexcept, а копирование-в противном случае (если конструктор копирования недоступен, но потенциально вызывающий конструктор перемещения доступен, и в этом случае гарантия сильного исключения отменяется).

Noexcept-это улучшенная версия throw (), которая устарела в C++11. В отличие от throw(), noexcept не вызывает std:: unexpected и может или не может разматывать стек, что потенциально позволяет компилятору реализовать noexcept без накладных расходов времени выполнения throw ().

Для более подробно, пожалуйста, посетите следующие веб-сайты

Редактировать: пример кода, чтобы проиллюстрировать вышеуказанные пункты.

// whether foo is declared noexcept depends on if the expression
// T() will throw any exceptions, check in compile time
template <class T>
void foo() noexcept(noexcept(T())) {     
}

void bar() noexcept(true) {    
}

void baz() noexcept {
    throw 42;     
}  // noexcept is the same as noexcept(true)

int main() 
{
    foo<int>();  // noexcept(noexcept(int())) => noexcept(true), so this is fine

    bar();  // fine
    baz();  // compiles, but at runtime this calls std::terminate
}

noexcept указывает, что функция предназначена не для того, чтобы выдавать исключение, гарантию, которую вы, как разработчик, предоставляете, то есть не принуждается компилятором. Поэтому использовать его в ситуации, когда ваша функция вызывает функции, которые могут выдавать исключения, которые вы не ловите сами, плохо.

Весь диапазон спецификаторов throw() был удален, поскольку спецификаторы исключений были менее оптимальными в C++, см.: разница между спецификатором c++03 throw() C++11 noexcept

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

Использование этого, может быть, например, в унаследованной структуре класса, где один суперкласс хочет "принудить" унаследованный класс, что конкретная виртуальная функция не может создать исключение. Далее компилятор может использовать эту информацию для оптимизация.

noexcept является также оператором, который может вычислять выражение и возвращать, может ли это выражение вызывать исключение или нет, в соответствии с § 5.3.7.

5.3.7 оператор noexcept [expr.унарный.noexcept]

1 оператор noexcept определяет, является ли оценка его операнда, который является ненулевым операндом (Пункт 5), может вызвать исключение (15.1). noexcept-выражение: noexcept (выражение)

2 результат noexcept оператор-это константа типа bool и rvalue.

3 результат оператора noexcept является ложным, если в потенциально оцениваемом контексте выражение будет содержать

- потенциально оцениваемый вызов функции, функции-члена, указателя функции или указателя функции-члена, который не имеет спецификации исключения (15.4), если вызов не является константой выражение (5.19),
- потенциально оцененное выражение броска (15.1),
- ля потенциально оцениваемое выражение dynamic_cast dynamic_cast(v), где T-ссылочный тип, требующий проверки во время выполнения (5.2.7), или
- потенциально оцениваемое выражение typeid (5.2.8), применяемое к выражению glvalue, тип которого является полиморфным типом класса (10.3).
В противном случае результат будет истинным.

Я не могу объяснить возможные оптимизации так же хорошо, как Скотт Мейерс: http://aristeia.com/EC++11-14 / noexcept%202014-03-31. pdf из его поста в блоге: объявлять функции noexcept, когда это возможно?

Разница между разматыванием стека вызовов и возможным его разматыванием оказывает удивительно большое влияние на генерацию кода. В функции noexcept оптимизаторам не нужно поддерживать стек времени выполнения в состоянии unwindable, если исключение будет распространяться из функции, и они не должны гарантировать, что объекты в функции noexcept будут уничтожены в обратном порядке построения, если исключение покинет функцию. В результате появляется больше возможностей для оптимизации, причем не только в теле функции noexcept, но и на участках, где эта функция вызывается. Такая гибкость присутствует только для функций noexcept. Функции с" throw () " спецификациями исключений не имеют его, как и функции без спецификации исключений вообще.

Я публикую 2 фрагмента кода, чтобы объяснить вашу проблему:

Код 1:

#include <iostream>
using namespace std;
void foo() noexcept     // see the noexcept specifier
{
    throw 42;
}
int main()
{
    try
    {
        foo();
    }
    catch(...)
    {
        cerr<<"exception caught\n";
    }
    return 0;
}

Здесь выход будет: -

terminate called after throwing an instance of 'int'

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

Если я удалю noexcept, то:

Код 2:

#include <iostream>
using namespace std;
void foo()    // noexcept is eliminated
{
    throw 42;
}
int main()
{
    try
    {
        foo();
    }
    catch(...)
    {
        cerr<<"exception caught\n";
    }
    return 0;
}

Вывод будет: -

exception caught

Потому что foo был подписан как noexcept, следовательно, terminate был назван.

Наследование конструкторов и неявно объявленных конструкторов по умолчанию, конструкторов копирования, конструкторов перемещения, деструкторов, операторов присваивания копий и по умолчанию все операторы присваивания перемещений являются noexcept(true), если только они не требуются для вызова функции, которая является noexcept(false), и в этом случае эти функции являются noexcept(false).

Вы также можете написать такие строки, как:

cout << boolalpha << noexcept(foo);   // here noexcept acts as 
                                     // an operator instead of a specifier

Приведенная выше строка проверит, будет ли foo бросать exception или нет. Если он бросит, то возвращаемое значение будет true else false.

Вы можете прочитать больше об этом в этом разделе.: http://scottmeyers.blogspot.dk/2014/03/declare-functions-noexcept-whenever.html

Comments

    Ничего не найдено.