2013-04-19 37 views
21

Là trình chỉ định hàm noexcept nhằm cải thiện hiệu suất vì không có khả năng mã lưu giữ sách cho các ngoại lệ trong đối tượng đã tạo và do đó phải được thêm vào khai báo hàm và định nghĩa bất cứ khi nào có thể? Tôi nghĩ về hàm bao cho các đối tượng có thể gọi ở nơi đầu tiên, trong đó noexcept có thể tạo ra một số khác biệt, mặc dù các biểu thức kiểm tra có thể "sưng lên" mã nguồn. Nó có đáng không?Không nhận thức được cải thiện hiệu suất?

+2

Tôi nghĩ rằng một trình biên dịch có thể làm điều đó, nhưng tôi nghĩ điểm là cho phép các mẫu để hành xử khác nhau khi họ không thể ném một ngoại lệ (có một 'hành noexcept' trả về 'false' khi biểu thức đối số có thể trả về một ngoại lệ - nó không trả về true nếu bạn có một hàm sẽ không bao giờ ném nhưng không được gắn thẻ với 'noexcept' mặc dù). – Cubic

+0

Nếu một hàm được khai báo là 'noexcept' ném chương trình phải kết thúc. Trình biên dịch cần tiêm ít nhất một số mã xử lý ngoại lệ để nắm bắt vấn đề và chấm dứt chương trình. –

+0

@ DavidRodríguez-dribeas: mã đó có thể là out-of-line, mặc dù (một phần của thời gian chạy C++, thậm chí). Về nguyên tắc, cơ chế xử lý ngoại lệ có thể đi lên ngăn xếp và cho từng khung cuộc gọi, kiểm tra xem mã của nó có được gắn cờ "cờ không đánh dấu" hay không. Có lẽ với sự phức tạp hơn để đối phó với các cuộc gọi nội tuyến không có khung hình riêng của họ. Cho dù đó là những gì trình biên dịch thực sự làm cho 'noexcept', tôi không chắc chắn, nhưng thường nó là làm thế nào họ tìm kiếm xử lý ngoại lệ và cũng cho công việc phải được thực hiện trong quá trình thư giãn stack. –

Trả lời

8

Các trình biên dịch hàng đầu tạo mã đã được tối ưu hóa rất nhiều giống như mã không thể ném, và sau đó trường hợp ngoại lệ xảy ra được xử lý bằng mã ngoài dòng mà cơ chế xử lý ngoại lệ tìm thấy bằng cách xem meta -data liên quan đến hàm. Tôi cho rằng có một số lợi ích trong kích thước mã để bỏ qua điều này khi nó được biết là không cần thiết, mặc dù.

Có lẽ một số trường hợp đặc điểm kỹ thuật nothrow không cho phép một số tối ưu hóa cụ thể:

int main() { 
    int i = 0; 
    try { 
     ++i; 
     thing_that_cannot_throw(); 
     ++i; 
     thing_that_can_throw(); 
     ++i; 
    } catch (...) {} 
    std::cout << i << "\n"; 
} 

Ở đây, thứ hai ++ tôi có thể về mặt lý thuyết được sắp xếp lại trước khi cuộc gọi đến thing_that_cannot_throw (và i chỉ khởi tạo 2) . Cho dù thực tế là một vấn đề khác, mặc dù, kể từ khi triển khai thực hiện bảo đảm về trạng thái của các biến trong trình gỡ lỗi hoặc trong ngăn xếp phía trên một cuộc gọi hàm, sẽ muốn i để có giá trị 1 trong cuộc gọi đó mặc dù đó là biến cục bộ không thể quan sát được theo bất kỳ phương thức tiêu chuẩn nào.

Tôi nghi ngờ rằng các đảm bảo không đảm bảo có giá trị hơn đối với người lập trình so với trình biên dịch. Nếu bạn đang viết mã cung cấp bảo đảm ngoại lệ mạnh thì thường sẽ có một số hoạt động quan trọng mà bạn thực hiện, rằng bạn cần phải cung cấp bảo đảm không đảm bảo (hoán đổi, di chuyển và phá hủy là các ứng viên phổ biến).

+0

Và dĩ nhiên, chúng ta có thể có các cảnh báo * về việc có ngoại lệ có thể được ném từ bên trong các hàm 'noexcept' để giúp chúng ta đi bộ ... mặc dù không may với C++ vấn đề phổ biến của' mới' có thể ném nhiều ngăn: ( –

+0

@MatthieuM. Có một phiên bản mới, không có? – Martin

+1

@Martin: có, std :: string' sử dụng cái gì? Vấn đề là bạn không thể tạo một chuỗi 'std :: mới 'trong một phương thức' noexcept', không phải vì mã của bạn thiếu sót, nhưng vì phần cứng bạn chạy có thể bị hạn chế hơn, nó khá là khó chịu. –

11

Về mặt lý thuyết, noexcept sẽ cải thiện hiệu suất. Nhưng nó cũng có thể gây ra một số vấn đề.

Trong hầu hết các trường hợp, không được chỉ định vì các ưu điểm quá ít để được xem xét và có thể làm cho mã của bạn nâng cấp đau đớn. This post, được viết bởi Andrzej, giới thiệu các lý do chi tiết.

Nếu nó quá dài, chỉ cần mang những gợi ý tôi kết luận từ nó:

  1. chức năng Annotate với noexcept nếu
    • họ đã chú thích với throw() đã có,
    • hoặc họ là ứng cử viên tốt (được liệt kê trong bài đăng) và không bao giờ ném chắc chắn,
    • hoặc chúng là các nhà xây dựng di chuyển, bài tập di chuyển có chú thích noexcept không thể được trình bày chính xác bởi trình biên dịch và các trường hợp của chúng là được đưa vào một số container STL.
  2. Đừng chú thích các chức năng với noexcept nếu
    • bạn đang thực sự quan tâm đến giảm hiệu suất,
    • hoặc về nguy cơ gọi std::terminate,
    • hoặc bạn chỉ là không chắc chắn về các tính năng mới ,
    • hoặc bạn có nghi ngờ liệu bạn có nên thực hiện chức năng của mình noexcept hay không.
Các vấn đề liên quan