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)
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. C++ exception specifications from throw() to noexcept: move operations, swap, destructors, conditional noexcept, and why… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
이 글에서 다루는 키워드 (관련 검색어)
C++, Exception Specifications, noexcept, throw, Deprecated 등으로 검색하시면 이 글이 도움이 됩니다.