Chuyển tới nội dung chính

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 noexceptMô tả
Tối ưu tốt hơnCho 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 runtimeNế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ợ STLSTL 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ĩaCó thể ném ngoại lệ?
noexceptMặc định là noexcept(true)Không
noexcept(true)Hàm cam kết không némKhông
noexcept(false)Hàm có thể ném ngoại lệ
noexcept(expr)Trả về true/false tùy biểu thứcTù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.