C++ Exception Specifications: noexcept, History, and throw() Removal
이 글의 핵심
Practical guide to C++ exception specifications: noexcept basics, history of throw(), move/swap patterns, and destructor rules.
Introduction
Exception specifications describe what exceptions a function may throw.
1. History of exception specifications
C++03 — throw()
// No exceptions
void func() throw();
// Specific types
void func() throw(std::exception);
void func() throw(int, double);
// Removed in C++17
C++11 — noexcept
// No exceptions
void func() noexcept;
// Conditional
void func() noexcept(true); // noexcept
void func() noexcept(false); // may throw
2. noexcept basics
Basic usage
#include <iostream>
void safe_func() noexcept {
std::cout << "no throw" << std::endl;
}
void risky_func() {
throw std::runtime_error("error");
}
int main() {
safe_func();
try {
risky_func();
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
return 0;
}
Checking noexcept
#include <iostream>
#include <type_traits>
void func1() noexcept {}
void func2() {}
int main() {
std::cout << std::boolalpha;
std::cout << "func1: " << noexcept(func1()) << std::endl; // true
std::cout << "func2: " << noexcept(func2()) << std::endl; // false
return 0;
}
3. Move operations and noexcept
Move constructor
#include <vector>
#include <iostream>
class Widget {
public:
Widget() = default;
Widget(Widget&& other) noexcept
: data(std::move(other.data)) {
std::cout << "move ctor" << std::endl;
}
Widget(const Widget& other)
: data(other.data) {
std::cout << "copy ctor" << std::endl;
}
private:
std::vector<int> data{1, 2, 3};
};
int main() {
std::vector<Widget> vec;
vec.reserve(10);
Widget w;
vec.push_back(std::move(w)); // move ctor (noexcept)
return 0;
}
Important: std::vector often requires noexcept move constructors to move elements during reallocation.
4. swap and noexcept
swap implementation
class Data {
public:
Data(int v) : value(v) {}
void swap(Data& other) noexcept {
std::swap(value, other.value);
}
int getValue() const noexcept { return value; }
private:
int value;
};
namespace std {
template<>
void swap(Data& lhs, Data& rhs) noexcept {
lhs.swap(rhs);
}
}
int main() {
Data d1(10), d2(20);
std::swap(d1, d2);
std::cout << d1.getValue() << std::endl; // 20
std::cout << d2.getValue() << std::endl; // 10
return 0;
}
5. Conditional noexcept
Templates and noexcept
template<typename T>
class Container {
public:
Container(Container&& other)
noexcept(std::is_nothrow_move_constructible_v<T>)
: data(std::move(other.data)) {}
void clear() noexcept(std::is_nothrow_destructible_v<T>) {
data.clear();
}
private:
std::vector<T> data;
};
6. Destructors and noexcept
Implicit noexcept
class MyClass {
public:
// destructor implicitly noexcept unless a member’s dtor can throw
~MyClass() {
// throwing here -> std::terminate during stack unwind
}
};
class Explicit {
public:
~Explicit() noexcept {
// still must not throw
}
};
Exceptions in destructor cleanup
class SafeClass {
public:
~SafeClass() noexcept {
try {
cleanup();
} catch (const std::exception& e) {
std::cerr << "cleanup error: " << e.what() << std::endl;
}
}
private:
void cleanup() {
// may throw
}
};
7. Practical example: resource management
#include <iostream>
#include <memory>
class Resource {
public:
Resource() {
std::cout << "allocate" << std::endl;
}
~Resource() noexcept {
std::cout << "release" << std::endl;
}
void use() noexcept {
std::cout << "use" << std::endl;
}
};
class Manager {
public:
Manager() : res(std::make_unique<Resource>()) {}
Manager(Manager&& other) noexcept
: res(std::move(other.res)) {}
Manager& operator=(Manager&& other) noexcept {
res = std::move(other.res);
return *this;
}
void process() noexcept {
if (res) {
res->use();
}
}
private:
std::unique_ptr<Resource> res;
};
int main() {
Manager m1;
m1.process();
Manager m2 = std::move(m1);
m2.process();
return 0;
}
Summary
Key points
- noexcept: C++11 exception contract
- throw(): deprecated (removed in C++17)
- Move operations: mark noexcept when safe
- Destructors: implicitly noexcept in normal cases
- Conditional:
noexcept(expression)
When to use noexcept
| Function | noexcept? | Reason |
|---|---|---|
| Move ctor | Yes | Container performance |
| Move assign | Yes | Container performance |
| swap | Yes | Exception safety |
| Destructor | Yes (default) | Avoid terminate during unwind |
| Simple getters | Often | No throws |
| Complex logic | Maybe not | May throw |
Next steps
- C++ noexcept
- Exception handling
- Move semantics
Related posts
- Exception handling
- noexcept specifier
- noexcept keyword
- Exception basics (series)
- Exception safety (series)