2008-12-15 29 views
9

Tôi tìm thấy một số mã trong một dự án mà trông như thế:Việc nắm bắt ngoại lệ trong chính (...) có ý nghĩa không?

int main(int argc, char *argv[]) 
{ 
    // some stuff 

try { 
    theApp.Run(); 
} catch (std::exception& exc) { 
    cerr << exc.what() << std::endl; 
    exit(EXIT_FAILURE); 
} 
return (EXIT_SUCCESS); 
} 

Tôi không hiểu tại sao các trường hợp ngoại lệ đang được đánh bắt. Nếu không, ứng dụng sẽ đơn giản thoát ra và ngoại lệ sẽ được in.

Bạn có thấy lý do chính đáng nào để bắt ngoại lệ ở đây không?


EDIT: Tôi đồng ý rằng bạn nên in lỗi ngoại lệ. Tuy nhiên, nó sẽ không được tốt hơn để rethrow ngoại lệ? Tôi có cảm giác rằng chúng tôi đang nuốt nó ở đây ...

+0

Làm thế nào để nuốt nó? Mã in thông báo ngoại lệ, và sau đó thoát ra. bạn có thể làm gì hơn? Nếu bạn rút lại ngoại lệ, ai sẽ thấy nó? Nó sẽ bị bắt ở đâu? Đây là điểm vào của chương trình, sau khi tất cả. – jalf

Trả lời

15

Nếu ngoại lệ không được bắt buộc thì tiêu chuẩn không xác định liệu ngăn xếp có bị bỏ trống hay không. Vì vậy, trên một số nền tảng destructors sẽ được gọi, và trên những người khác chương trình sẽ chấm dứt ngay lập tức. Việc nắm bắt ở cấp cao nhất đảm bảo rằng các destructor luôn được gọi.

Vì vậy, nếu bạn không chạy dưới trình gỡ rối, có thể bạn nên nắm bắt mọi thứ: (...) cũng như std :: exception. Sau đó, mã ứng dụng của bạn có thể làm sạch với RAII ngay cả trên một ngoại lệ chết người. Trong nhiều trường hợp như vậy bạn không thực sự cần phải dọn dẹp, vì hệ điều hành sẽ làm điều đó cho bạn. Nhưng ví dụ bạn có thể muốn ngắt kết nối sạch từ các dịch vụ từ xa nếu có thể và có thể có các tài nguyên bên ngoài quy trình, chẳng hạn như các đường ống/mutexes được đặt tên mà bạn muốn hủy thay vì bị rò rỉ.

Làm lại ngoại lệ trong trường hợp có vẻ như tôi bị hạn chế sử dụng, vì bạn đã mất ngữ cảnh trong đó ban đầu nó bị ném. Tôi giả sử rằng bẫy một ngoại lệ không bị bắt trong trình gỡ lỗi là noisier hơn là chỉ cần đăng nhập các lỗi để std :: cerr, do đó, rethrowing sẽ là di chuyển thông minh nếu có một cơ hội thiếu đăng nhập.

Nếu bạn muốn trình gỡ rối bẫy các điều kiện bất ngờ trong chế độ gỡ lỗi, trong chế độ phát hành, hãy thoát ngoại lệ mà cuối cùng dẫn đến thoát, có nhiều cách khác để thực hiện điều đó. .Ví dụ: bạn có thể sử dụng macro khẳng định. Tất nhiên, điều đó không giúp đỡ với các điều kiện bất ngờ và không thể đoán trước, như trường hợp ngoại lệ phần cứng nếu bạn đang sử dụng SEH trên .NET.

6

Tại sao bạn nói rằng ngoại lệ sẽ được in? Đây không phải là hành vi điển hình của thời gian chạy C++. Tốt nhất, bạn có thể mong đợi rằng loại của nó được in.

Ngoài ra, chương trình này để lại trạng thái "lỗi", trong khi ngoại lệ có thể gây ra trạng thái chấm dứt thông báo hủy bỏ (tức là có tín hiệu được chỉ ra trong mã thoát).

+0

Bạn nói đúng, tôi nhầm tưởng rằng ngoại lệ sẽ được in. Thực tế không phải là như vậy. – Barth

3

Đây là khối bắt toàn cầu. Nó được phổ biến để hiển thị một thông điệp tốt đẹp và người dùng hiểu ('Lỗi nội bộ') thay vì một ngoại lệ khó hiểu in ra. Điều này có thể không hiển nhiên từ khối mã cụ thể, nhưng nói chung là một ý tưởng hay.

+0

Nó chỉ là một ý tưởng tốt, cho đến khi lần đầu tiên bạn phải gỡ lỗi một số ngoại lệ bí ẩn, đó là ném từ địa ngục biết nơi ... :) – Paulius

+1

sau đó chúng ta không thể in nó và rethrow nó? – Barth

+0

Tôi đoán chúng ta có thể, nhưng khi tôi đang gỡ lỗi - tôi hiếm khi nhìn vào những gì được in - tôi thường xem xét các giá trị trong cửa sổ xem (nếu cần). – Paulius

6

Thử nắm bắt trong chức năng chính ẩn ngoại lệ khỏi trình gỡ lỗi. Tôi sẽ nói, nó không tốt.

Mặt khác, khách hàng không được dự kiến ​​sẽ có trình gỡ rối, vì vậy việc bắt ngoại lệ rất tốt. Vì vậy, nó là tốt.

Cá nhân, tôi bắt tất cả ngoại lệ trong chức năng chính, khi tạo bản phát hành và tôi không làm điều đó khi xây dựng cấu hình gỡ lỗi.

0

Hãy xem qua kinh thánh C++, ví dụ: Stroustrup, anh ta có một ví dụ được lặp lại trong lập trình C++ ứng dụng. Lý do là:

int main(void) 
{ 
    try 
    { 
      // your code 
    } 
    catch (/* YourPossibleExceptions i.e. barfs you expect may occur */) 
    { 
    } 
    catch (...) // unexpected errors, so you can exit gracefully 
    { 
    } 
} 
+0

Có. Nhưng như tôi đã đề cập trong câu trả lời của tôi - nó không thực sự giúp trình gỡ lỗi. Nếu ngoại lệ không bị bắt - trình gỡ lỗi sẽ hiển thị cho bạn vị trí chính xác trong nguồn, nơi ngoại lệ được ném. Vì vậy, điều này chỉ có ý nghĩa trong bản phát hành bản phát hành. – Paulius

4

Một ví dụ đơn giản của một tình huống mà chồng không thư giãn:
Why destructor is not called on exception?

Một danh sách các trường hợp ngoại lệ có thể gây ra các ứng dụng để chấm dứt chứ không phải là thư giãn stack.
Why destructor is not called on exception?

Nếu một ngoại lệ không được bắt ở bất kỳ cấp độ và sẽ thoát khỏi main() sau đó thực hiện được phép gọi chấm dứt() đúng hơn là tháo ngăn xếp (có này bắt tôi ngạc nhiên là tốt).

Kết quả là tôi luôn bắt tất cả ngoại lệ trong chính().

int main() 
{ 
    try 
    { 
    } 
    catch(std::exception const& e) 
    { /* LOG */ 
     // optimally rethrow 
    } 
    catch(...) // Catch anything else. 
    { /* LOG */ 
     // optimally rethrow 
    } 
} 

Để giúp khắc phục sự cố khi gỡ lỗi. Xuất phát ngoại lệ của bạn từ std :: exception và sau đó dính điểm ngắt trong hàm tạo cho std :: exception.

0

Theo thông số kỹ thuật của Windows, main không được phép ném. (thực tế nó kết quả vào thông báo hỏi bạn có muốn gửi báo cáo lỗi cho Microsoft)

+1

Có thể bạn có thể liên kết đến thông số kỹ thuật của Windows nơi nó nói điều này không? điều đó sẽ cung cấp một số ngữ cảnh/thẩm quyền bổ sung cho câu trả lời của bạn. – jadarnel27

Các vấn đề liên quan