C++ Exception Specifications: noexcept, History, and throw
이 글의 핵심
C++ exception specifications from throw() to noexcept: move operations, swap, destructors, conditional noexcept, and why dynamic specs were removed.
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
Related posts
- Exception handling
- noexcept specifier
- noexcept keyword
- Exception basics (series)
- Exception safety (series)
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. C++ exception specifications from throw() to noexcept: move operations, swap, destructors, conditional noexcept, and why…
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
Keywords Covered in This Article (Related Search Terms)
This article covers C++, Exception Specifications, noexcept, throw, Deprecated.