2012-10-16 61 views
5

Học "try & catch". Có gì sai với đoạn mã sau? Cảm ơn lời khuyên.c + + xử lý ngoại lệ

Lỗi trong thực hiện:

terminate called without an active exception 
Aborted 

Mã:

#include <stdio.h> 
int main() 
{ 
    int a = 3; 

    try 
    { 
    if (a < 5) 
     throw; 
    } 
    catch (...) 
    { 
    printf ("captured\n"); 
    } 

    return 0; 
} 
+0

bằng cách mã của bạn trông C_ish_ hơn so với C++ _ ish_, chỉ cần làm quen với mã trong C++ nếu bạn chọn C++ là ngôn ngữ của sự lựa chọn, cách này mã của bạn có thể dễ dàng trở thành một sự pha trộn kỳ lạ của ngôn ngữ mà không có bất kỳ lợi ích nào cả và chỉ có thể làm cho cuộc sống của bạn khó học không có gì mới và hữu ích. Đúng là C được hỗ trợ theo C++ mà không có vấn đề gì, nhưng chỉ cố gắng có một cách tiếp cận đơn giản hơn và tuyến tính hơn khi mã hóa. – Ken

Trả lời

4

Bên trong của một khối try, bạn phải xác định để ném. Nơi duy nhất bạn có thể sử dụng throw của chính nó là bên trong một khối catch để ném lại ngoại lệ hiện tại. Nếu bạn tự gọi throw mà không có ngoại lệ hiện tại đang hoạt động, bạn sẽ giết ứng dụng của mình, như bạn đã khám phá.

Hãy thử điều này:

#include <stdio.h> 

int main() 
{ 
    int a = 3; 

    try 
    { 
    if (a < 5) 
     throw 1; // throws an int 
    } 
    catch (...) 
    { 
    printf ("captured\n"); 
    } 

    return 0; 
} 

Bạn có thể throw bất cứ điều gì bạn muốn, miễn là bạn ném một cái gì đó.

+0

Đó là một chút mơ hồ để nói '[bạn phải sử dụng' ném' của chính nó bên trong một khối 'catch'], bởi vì nó cho thấy một giới hạn cú pháp.Trong sự thật thì không sao khi bất cứ khi nào ngoại lệ hoạt động - bất kể phạm vi. –

+0

@LucDanton: Tôi đã không nói rằng bạn phải sử dụng 'ném' của chính nó, tôi nói rằng nơi duy nhất bạn có thể sử dụng 'ném' của chính nó là bên trong một 'catch'. Không có ngoại lệ hoạt động nếu bạn không ở trong một 'catch'. –

+0

[Ví dụ chính xác khi 'ném;' không được sử dụng cú pháp bên trong khối 'catch'] (http://liveworkspace.org/code/85bfc976aec21b24d65293ce9355b7cb). –

5

tuyên bố throw; bạn cố gắng rethrow một ngoại lệ hiện tại nhưng có lẽ không phải là một. Bạn cần một cái gì đó giống như

throw some_exception_object(); 
+2

Tôi muốn khuyên bạn nên 'ném std :: runtime_error (" message ")', nhưng tôi đã thấy 'ném 42' (mà tôi tin rằng chỉ có thể bị bắt với 'catch (...)'). –

+1

@MaxLybbert: Nó có thể bị bắt với 'catch (int n)', nhưng vâng, việc ném các loại không phải lớp không được khuyến khích cho các chương trình "thực". – aschepler

+0

Cảm ơn, tôi vừa thử nghiệm và 'catch (int i)' hoạt động. –

1

Bạn cần thực sự ném một số đối tượng. Ngay cả một cái gì đó đơn giản như

throw "error"; 

sẽ bắt lỗi như bạn muốn.

xem hoạt động here

4

Có bốn điều, hai lớn và hai nhỏ. Một điều tại một thời điểm ...

1. rethrow sử dụng w/o ngoại lệ hoạt động

Một tuyên bố throw; được sử dụng để tái ném một ngoại lệ mà hiện tại đang bắt. Ví dụ:

try { 
    do_something(); 
} catch (const std::exception &) { 
    throw; // This statement re-throws an exception that was caught in this "catch" block. 
} 

Trong trường hợp của bạn, bạn đang sử dụng throw; mà không đánh bắt bất kỳ trường hợp ngoại lệ (hay nói cách trật tự - nó không xuất hiện bên catch khối trực tiếp hoặc gián tiếp), do đó chương trình của bạn được chấm dứt. Khi có nhu cầu ném và không ném lại một ngoại lệ, như trong trường hợp của bạn, bạn phải chỉ định một đối tượng ngoại lệ được ném. Ví dụ:

throw std::runtime_error("Something bad happened"); 

2. nhận tất cả điều khoản mà không tái ném một ngoại lệ bắt

nhận tất cả bạn khoản (catch (...)) là hoàn toàn hợp pháp C++. Tuy nhiên, nó không tái ném ngoại lệ bị bắt. Mặc dù nó là một mã C++ hợp pháp, việc sử dụng đó là một điều cấm kỵ. Thời gian chạy C và C++ thường sử dụng các loại ngoại lệ đặc biệt để thực hiện một số chức năng nhất định. Ví dụ: NPTL đang sử dụng ngoại lệ để thực hiện hủy bỏ chuỗi. Nếu bạn bắt được ngoại lệ đó bằng cách sử dụng catch (...), chuỗi sẽ không bị hủy và bạn sẽ có thời gian xấu. Nói chung, bạn phải bắt ngoại lệ theo loại của họ.Trong hầu hết các trường hợp, ngoại lệ được thừa kế từ std::exception và do đó bạn phải viết catch (const std::exception &) hoặc nếu bạn muốn bắt được loại chính xác, - catch(const TypeYouExpect &). Nếu bạn phải, tuy nhiên, sử dụng bắt tất cả, hãy nhớ để ném lại. Ví dụ:

try { 
    do_something(); 
} catch (...) { 
    throw; // DO NOT FORGET TO RE-THROW. 
} 

3. Tiêu đề đặt tên ...

Bạn đã bao gồm tiêu đề C trong khi C++ cung cấp tiêu đề riêng của mình cho các tính năng C chuẩn. Vì vậy, tiêu đề:

#include <stdio.h> 

.. nên là:

#include <cstdio> 

C++ chức năng C cụ thể được điều trị đặc biệt. Ví dụ, chúng trở nên có sẵn trong không gian tên std. Để bạn có thể sử dụng std::open() thay vì chỉ open() hoặc ::open(). Không có vấn đề lớn, nhưng là rất khuyến khích cách để đi.

4. Trở về từ chính.

Không giống như chức năng main() của C, C++ rất đặc biệt. Nó cho phép bạn không có return 0;. Đây là hành vi mặc định. Vì vậy, trừ khi bạn thực sự cần phải trả lại một số giá trị, bạn có thể tiết kiệm cho mình một thời gian bằng cách không gõ return 0;. Tuy nhiên, hãy nhớ rằng, main là chức năng duy nhất như vậy và ở mọi nơi khác, bạn phải trả lại một cách rõ ràng, trừ khi hàm được đánh dấu void.

Hy vọng điều đó sẽ hữu ích. Chúc may mắn!

1

Những tuyên bố để ném một ngoại lệ là:

throw <expression>; 

Tuyên bố này:

throw; 

còn được gọi là tuyên bố tái ném và được sử dụng để tái ném một ngoại lệ hiện có mà đã được bắt. Nó thường được sử dụng trong một khối catch, ví dụ, bạn nhìn vào ngoại lệ và quyết định xem bạn có thể tiếp tục, thử lại hay hủy bỏ. Trong trường hợp bạn quyết định hủy bỏ, bạn lại ném ngoại lệ để người khác xuống ngăn xếp cuộc gọi sẽ bắt và xử lý lỗi này.

Ví dụ:

// getResult() calls can fail with a deadlock exception 
// This method will retry up to 3 times before failing 
Result getResultWithRetry() 
{ 
    int nbTry = 3; 
    for(;;) { 
     try { 
      return getResult(); 
     } catch (DeadLockException& e) { 
      if (nbTry == 0) { 
       throw; // re-throw the deadlock exception 
      } 
     } 
     --nbTry; 
    } 
} 
+1

Gợi ý: bắt ngoại lệ do tham chiếu không liên tục vì không có lý do chính đáng là một thực tế không tốt. Trừ khi bạn thực sự cần phải sửa đổi các đối tượng, bắt bằng tham chiếu liên tục. Điều này cho phép trình biên dịch thực hiện tối ưu hóa hơn. –