Từ khóa noexcept và Best Practice
1. noexcept
là gì?
Từ khóa noexcept
được giới thiệu từ C++11 để chỉ định rằng một hàm không ném ngoại lệ. Cú pháp:
void func() noexcept; // cam kết không ném
void func() noexcept(true); // tương đương
void func() noexcept(false); // không cam kết
Nếu một ngoại lệ bị ném trong hàm noexcept
, chương trình sẽ gọi std::terminate()
ngay lập tức, không qua catch
.
2. Tác dụng chính của noexcept
- Giúp trình biên dịch tối ưu tốt hơn: giảm chi phí kiểm tra ngoại lệ, inline hiệu quả hơn.
- Bảo vệ tại runtime: nếu ngoại lệ không được mong đợi xảy ra,
std::terminate()
được gọi ngay. - Tăng độ rõ ràng API: biểu thị ý định rằng hàm an toàn, không ném lỗi.
3. Khi nào nên dùng?
Nên dùng noexcept
khi:
- Hàm đơn giản, chỉ tính toán logic không ném (vd: toán tử so sánh, hàm getter).
- Hàm không gọi hàm khác có thể ném ngoại lệ.
- Destructor, move constructor/assignment nên đánh dấu
noexcept
để container STL tối ưu:class MyType {
public:
MyType(MyType&& other) noexcept; // tốt cho vector/move
~MyType() noexcept; // destructor nên noexcept
};
Tránh dùng noexcept
khi:
- Hàm có thể ném, hoặc gọi các hàm có thể ném mà bạn không kiểm soát.
- Bạn muốn truyền ngoại lệ (dùng
try/catch
bên ngoài để xử lý).
4. Phân tích hiệu suất và an toàn
Lợi ích của noexcept | Mô tả |
---|---|
Tối ưu tốt hơn | Cho phép trình biên dịch bỏ qua code kiểm tra ngoại lệ, inline dễ hơn. |
Tăng an toàn runtime | Nếu bạn đánh dấu noexcept , nghĩa là bạn chắc chắn không ném lỗi. Nếu sai → terminate, giúp phát hiện lỗi sớm. |
Hỗ trợ STL | STL yêu cầu move constructor phải noexcept để tối ưu hóa trong container như std::vector . |
5. So sánh noexcept
, noexcept(true)
, noexcept(false)
Cú pháp | Ý nghĩa | Có thể ném ngoại lệ? |
---|---|---|
noexcept | Mặc định là noexcept(true) | Không |
noexcept(true) | Hàm cam kết không ném | Không |
noexcept(false) | Hàm có thể ném ngoại lệ | Có |
noexcept(expr) | Trả về true /false tùy biểu thức | Tùy điều kiện |
Ví dụ:
template <typename T>
void swap(T& a, T& b) noexcept(noexcept(T(std::move(a)))) {
T tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
noexcept(...)
giúp viết mã tổng quát an toàn và tối ưu.
6. Best practice tóm tắt
Dùng noexcept
:
- Với hàm không ném lỗi.
- Với move constructor/assignment nếu nội dung không ném.
- Với destructor (luôn nên
noexcept
).
Không dùng noexcept
:
- Khi có khả năng ném ngoại lệ.
- Khi bạn không kiểm soát logic hàm con bên trong.