Ce face noexcept
noexcept după o funcție este o promisiune: funcția nu lasă nicio excepție să iasă din ea. Dacă totuși iese una, programul nu caută catch, ci se oprește imediat cu std::terminate.
Promisiunea ajută la optimizare. Cel mai important caz: std::vector își mută elementele la mărire doar dacă constructorul de mutare al tipului este noexcept (sau dacă tipul nu se poate copia); altfel le copiază, ceea ce e mai lent. Destructorii sunt noexcept implicit.
Ca operator, noexcept(expresie) dă true sau false la compilare, fără să execute expresia. Se folosește în șabloane: void f() noexcept(noexcept(g())).
Exemple
Exemplul 1: Operatorul noexcept
#include <print>
#include <string>
int dublu(int x) noexcept { return x * 2; }
int converteste(const std::string& s) { return std::stoi(s); }
int main() {
std::println("dublu poate arunca: {}", !noexcept(dublu(2)));
std::println("converteste poate arunca: {}", !noexcept(converteste("2")));
std::println("dublu(21) = {}", dublu(21));
}
Rezultat
dublu poate arunca: false
converteste poate arunca: true
dublu(21) = 42
Exemplul 2: Mutare noexcept și std::vector
La mărirea vectorului, elementele de tip Rapid (mutare noexcept) sunt mutate, iar cele de tip Lent sunt copiate, pentru că mutarea lor ar putea arunca la jumătatea operației.
#include <print>
#include <type_traits>
#include <vector>
struct Rapid {
Rapid() = default;
Rapid(const Rapid&) { std::println("Rapid: copiere"); }
Rapid(Rapid&&) noexcept { std::println("Rapid: mutare"); }
};
struct Lent {
Lent() = default;
Lent(const Lent&) { std::println("Lent: copiere"); }
Lent(Lent&&) { std::println("Lent: mutare"); }
};
int main() {
std::println("Rapid se mută fără excepții: {}", std::is_nothrow_move_constructible_v<Rapid>);
std::vector<Rapid> a(1);
a.reserve(10); // mărire: elementul existent este mutat
std::vector<Lent> b(1);
b.reserve(10); // mărire: elementul existent este copiat
}
Rezultat
Rapid se mută fără excepții: true
Rapid: mutare
Lent: copiere
Greșeli frecvente
- Marchezi
noexcepto funcție care apelează cod ce poate arunca (de exemplu alocare de memorie,std::stoi). Dacă excepția apare, programul se oprește brusc custd::terminate, fără nicio șansă de tratare. - Uiți
noexceptla constructorul și operatorul de mutare scrise de tine. Containerele standard vor copia obiectele în loc să le mute.
Comenzi înrudite
try, catch: try marchează codul care poate arunca o excepție, iar blocurile catch prind și tratează excepțiile de un anumit tip.throw: Aruncă o excepție: oprește execuția normală și trimite eroarea la cel mai apropiat catch potrivit.referințe (&, &&): O referință este un alt nume pentru o variabilă existentă; tot ce faci cu referința se face de fapt cu variabila originală.std::move: Mută elementele unui interval la o destinație, fără să le copieze (versiunea din <algorithm>).std::vector: Tabloul dinamic din C++: ține elementele unul după altul în memorie și își mărește singur dimensiunea.