2009-09-26 38 views
19

Hãy tưởng tượng hai mảnh tương tự như mã:Sự khác biệt giữa ném và ném với arg bị bắt ngoại lệ là gì?

try { 
    [...] 
} catch (myErr &err) { 
    err.append("More info added to error..."); 
    throw err; 
} 

try { 
    [...] 
} catch (myErr &err) { 
    err.append("More info added to error..."); 
    throw; 
} 

Là những hiệu quả tương tự hoặc để chúng khác nhau ở một số cách tinh tế? Ví dụ, cái đầu tiên có gây ra một hàm khởi tạo sao chép được chạy trong khi có lẽ lần thứ hai tái sử dụng cùng một đối tượng để cấu trúc lại nó?

Trả lời

26

Tùy thuộc vào cách bạn đã sắp xếp thứ bậc ngoại trừ của bạn, lại ném một ngoại lệ bằng cách đặt tên biến ngoại lệ trong báo cáo kết quả ném có thể lát đối tượng ngoại lệ ban đầu.

Một biểu ném không tham số sẽ ném các đối tượng ngoại lệ hiện tại giữ gìn loại năng động của nó, trong khi một biểu ném với một cuộc tranh cãi sẽ ném một ngoại lệ mới dựa trên tĩnh loại lập luận để throw.

Ví dụ:

int main() 
{ 
    try 
    { 
     try 
     { 
      throw Derived(); 
     } 
     catch (Base& b) 
     { 
      std::cout << "Caught a reference to base\n"; 
      b.print(std::cout); 
      throw b; 
     } 
    } 
    catch (Base& b) 
    { 
     std::cout << "Caught a reference to base\n"; 
     b.print(std::cout); 
    } 

    return 0; 
} 

Theo văn bản trên, chương trình sẽ ra:

Caught a reference to base 
Derived 
Caught a reference to base 
Base

Nếu throw b là thay thế với một throw, sau đó đánh bắt ngoài cũng sẽ bắt đầu ném Derived ngoại lệ. Điều này vẫn giữ nếu lớp bên trong bắt giữ ngoại lệ Base thay vì tham chiếu - mặc dù điều này có nghĩa là đối tượng ngoại lệ ban đầu không thể sửa đổi được, vì vậy bất kỳ thay đổi nào đối với b sẽ không được phản ánh trong ngoại lệ Derived. .

+1

Ah, tôi hoàn toàn quên mất việc cắt! Chết tiệt, điều đó quan trọng! Cảm ơn đã đưa ra vấn đề này. +1 (Mặc dù tôi nghĩ khi bạn viết "... giữ nguyên kiểu tĩnh ban đầu ..." nghĩa là _dynamic_ type. Kiểu gọi là _dynamic type_, sau khi tất cả, nếu không phải là _ "kiểu tĩnh ban đầu" _.) - – sbi

+1

Tuyệt vời tôi cũng hoàn toàn quên mất điều đó. – GManNickG

+0

Tôi rất vui vì ai đó đã gặp phải sự cố _slicing_;) –

16

Trong trường hợp thứ hai theo C++ chuẩn 15,1/6 constructor sao chép không được sử dụng:

Một ném biểu hiện không có toán hạng rethrows trừ được xử lý. Ngoại lệ được kích hoạt lại với tạm thời hiện tại; không có đối tượng ngoại lệ tạm thời mới được tạo. Ngoại lệ không còn bị coi là bị bắt; do đó, giá trị của uncaught_exception() sẽ lại đúng.

Trong trường hợp đầu tiên ngoại lệ mới sẽ được ném theo 15,1/3:

Một ném biểu hiện khởi tạo một đối tượng tạm thời, được gọi là đối tượng ngoại lệ, loại được xác định bằng cách loại bỏ bất kỳ cv-vòng loại cấp cao nhất từ ​​loại tĩnh của toán hạng ném và điều chỉnh loại từ “mảng T” hoặc “hàm trả về T” thành “con trỏ đến T” hoặc “con trỏ tới hàm trả về T”, tương ứng. < ...> Tạm thời được sử dụng để khởi tạo biến có tên trong trình xử lý đối sánh (15.3). Loại biểu thức ném không được là loại không đầy đủ hoặc con trỏ hoặc tham chiếu đến loại không đầy đủ, ngoài void *, const void *, void bay hơi *, hoặc const volatile void *. Ngoại trừ những hạn chế này và các hạn chế đối với sự kết hợp loại được đề cập trong 15.3, toán hạng ném được xử lý chính xác như một đối số hàm trong một cuộc gọi (5.2.2) hoặc toán hạng của câu lệnh trả về.

Trong cả hai trường hợp sao chép constructor là cần thiết ở giai đoạn ném (15,1/5):

Khi đối tượng ném là một đối tượng lớp, và các nhà xây dựng bản sao sử dụng để khởi tạo bản sao tạm thời không thể truy cập , chương trình không đúng định dạng (ngay cả khi đối tượng tạm thời có thể bị loại bỏ). Tương tự như vậy, nếu destructor cho đối tượng đó là không thể truy cập, chương trình là ill-hình thành (ngay cả khi các đối tượng tạm thời nếu không có thể được loại bỏ).

+0

Vì trình thu thập bản sao cần phải truy cập được đối với ngoại lệ được ném ban đầu, tôi không nghĩ đó là vấn đề trong trường hợp này. Nhưng bạn vẫn là một câu trả lời hay. +1 – sbi

+0

Có, nhưng trong trường hợp đầu tiên, bản sao c-tor sẽ được sử dụng hai lần. –

+1

Nó nói khi khai báo chỉ định một loại lớp. Tuy nhiên trong trường hợp của mình nó chỉ định một kiểu tham chiếu :) Tham chiếu sẽ bị ràng buộc trực tiếp và tham chiếu đến đối tượng ngoại lệ. Vì vậy, chúng tôi sẽ yêu cầu một bản sao ctor chỉ tại điểm ném, không bắt trong trường hợp này (Nó sẽ tạo ra một sự khác biệt khi một nhà xây dựng bản sao cơ sở được bảo vệ, ví dụ). –

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