2012-01-06 30 views
9

Scott Meyers nói:Nếu một ngoại lệ được ném luôn luôn là một bản sao của đối tượng ngoại lệ, tại sao không phải là hàm tạo bản sao này được gọi?

C++ xác định rằng một đối tượng ném một ngoại lệ như luôn sao chép và sao chép được thực hiện bởi nhà xây dựng bản sao của đối tượng.

Nhưng trong mã của tôi:

struct test 
{ 
    test() { cout << "constructor is called" << endl; } 
    test(const test&) { cout << "copy constructor is called" << endl; } 
    ~test() { cout << "destructor is called" << endl; } 
}; 

void fun() 
{ 
    throw test(); 
} 

int main() 
{ 
    try { 
     fun(); 
    } 
    catch (test& t1) { cout << "exception handler" << endl; } 
} 

Tôi không thấy constructor sao chép các đối tượng ngoại lệ của được gọi.

Nếu tôi thay đổi catch để nhận đối tượng ngoại lệ theo giá trị thì đúng vậy, nhưng theo lời Meyers, đối tượng ngoại lệ phải được sao chép ngay cả khi nó được nhận bằng tham chiếu.

Tại sao trình tạo bản sao không được gọi (ngay cả khi xử lý ngoại lệ được thực hiện theo tham chiếu)?

+2

Câu hỏi của bạn là gì? – cdeszaq

+5

Câu hỏi là "đó là sai: Meyers hoặc trình biên dịch của tôi?" Đừng đóng câu hỏi chỉ vì bạn không hiểu chúng. –

Trả lời

11

Meyers là đúng rằng một bản sao được thực hiện, ngữ nghĩa:

[C++11: 12.2/1]:temporaries của kiểu lớp được tạo ra trong những bối cảnh khác nhau: ràng buộc một tham chiếu đến một prvalue (8.5.3), trả lại một prvalue (6.6.3), một chuyển đổi tạo ra một giá trị (4.1, 5.2.9, 5.2.11, 5.4), ném một ngoại lệ (15.1), vào một trình xử lý (15.3) và trong một số lần khởi tạo (8.5). [..]

[C++11: 15.1/4]: Bộ nhớ cho bản sao tạm thời của ngoại lệ bị ném được phân bổ theo cách không xác định, ngoại trừ được ghi trong 3.7.3.1. Tạm thời tồn tại miễn là có một trình xử lý được thực hiện cho ngoại lệ đó.

Tuy nhiên, các bản sao có thể được các trình biên dịch thông minh ưu tiên và chúng được phép làm như vậy bất kể tác dụng phụ.

[C++11: 12.8/31]:Khi tiêu chí nhất định được đáp ứng, một thực hiện được phép bỏ qua việc xây dựng sao chép/di chuyển của một đối tượng lớp, ngay cả khi sao chép/di chuyển constructor và/hoặc destructor cho đối tượng có tác dụng phụ. Trong những trường hợp như vậy, việc triển khai xử lý nguồn và đích của thao tác sao chép/di chuyển bị bỏ qua chỉ đơn giản là hai cách khác nhau tham chiếu đến cùng một đối tượng và sự hủy diệt đối tượng đó xảy ra sau đó khi hai đối tượng bị phá hủy mà không cần tối ưu hóa. sự bỏ bớt này hoạt động sao chép/di chuyển, được gọi là bản sao sự bỏ bớt, được cho phép trong các trường hợp sau (có thể được kết hợp để loại bỏ nhiều bản sao):

  • [..]
  • khi một đối tượng lớp tạm thời không bị ràng buộc với tham chiếu (12.2) sẽ được sao chép/di chuyển đến đối tượng lớp với cùng loại cv không đủ điều kiện, hoạt động sao chép/di chuyển có thể bỏ qua bằng cách xây dựng đối tượng tạm thời trực tiếp vào mục tiêu của bản sao/di chuyển bị bỏ qua.
  • [..]
+3

Đối với 12.8/31 chúng tôi thực sự trong trường hợp tiếp theo, "khi một đối tượng lớp tạm thời không bị ràng buộc với tham chiếu (12.2) sẽ được sao chép/di chuyển đến một đối tượng lớp với cùng kiểu cv-unquali, bản sao/di chuyển hoạt động có thể được bỏ qua bằng cách xây dựng các đối tượng tạm thời trực tiếp vào mục tiêu của sao chép/di chuyển bị bỏ qua ". 'test()' là tạm thời, đối tượng ngoại lệ được cấp phát theo cách không xác định là đối tượng mà nó đang được sao chép/di chuyển, điều này cũng xảy ra tạm thời. Chúng tôi không nằm trong trường hợp bạn đánh dấu, vì toán hạng 'test()' không phải là tên của một đối tượng. –

+0

@SteveJessop: True. Ngoài ra tôi nghĩ rằng điều kiện liên quan đến phạm vi thất bại vì "chức năng gọi indirection" (thuật ngữ được thực hiện bởi tôi). –

+0

@SteveJessop: Trường hợp cuối cùng có liên quan không vì sự chấp nhận-by-ref? –

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