2012-02-03 36 views
17

Tôi đang tìm hiểu về thành ngữ RAII trong C++ và cách sử dụng con trỏ thông minh.RAII hoạt động như thế nào khi một nhà xây dựng đưa ra một ngoại lệ?

Trong bài đọc của mình, tôi đã bắt gặp hai điều mà đối với tôi, dường như mâu thuẫn lẫn nhau.

Quoted from http://www.hackcraft.net/raii/:

... nếu một đối tượng thành viên với ngữ nghĩa RAII đã được tạo và một ngoại lệ xảy ra trước khi các nhà xây dựng đã hoàn thành sau đó destructor của nó sẽ được gọi như là một phần của ngăn xếp ươm. Do đó, một đối tượng điều khiển nhiều tài nguyên có thể làm sạch chúng ngay cả khi nó không được xây dựng hoàn toàn bằng cách sử dụng các đối tượng RAII thành viên.

Nhưng trích dẫn từ http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10:

Nếu một constructor ném một ngoại lệ, destructor của đối tượng không được chạy. Nếu đối tượng của bạn đã làm điều gì đó cần được hoàn tác (chẳng hạn như cấp phát một số bộ nhớ, mở một tệp hoặc khóa một semaphore), "thứ cần được hoàn tác" này phải được ghi nhớ bởi một thành viên dữ liệu bên trong đối tượng.

Sau đó, nguồn được liên kết thứ hai đề xuất sử dụng con trỏ thông minh để giải quyết vấn đề của những thứ đã được phân bổ trong hàm tạo.

Vậy điều gì thực sự xảy ra trong các trường hợp này?

+8

+1 đây là cách mà "newprogrammer [s]" * nên * đặt câu hỏi! –

Trả lời

11

Bạn đang hiểu nhầm báo giá đầu tiên. Đó không phải là khó, vì nó khó hiểu.

nếu một đối tượng thành viên có ngữ nghĩa RAII được tạo và ngoại lệ xảy ra trước khi hàm tạo đã hoàn thành thì hàm hủy sẽ được gọi là một phần của thư giãn.

Đó là những gì nó nói. Dưới đây là những gì nó nghĩa:

nếu một đối tượng thành viên với ngữ nghĩa RAII đã được tạo và một ngoại lệ xảy ra trong đối tượng bên ngoài trước constructor các bên ngoài của đối tượng đã hoàn thành sau đó destructor đối tượng thành viên sẽ được gọi là một phần của thư giãn.

Xem sự khác biệt? Ý tưởng là đối tượng thành viên đã hoàn thành hàm tạo của nó, nhưng kiểu sở hữu thì không.Nó ném một nơi nào đó trong hàm khởi tạo của nó (hoặc một hàm tạo của một thành viên khác được khởi tạo sau cái đó). Điều này sẽ làm cho destructor của tất cả các thành viên của nó được gọi là (tất cả những người đã hoàn thành xây dựng, đó là), nhưng không phải là destructor riêng của nó.

Dưới đây là một ví dụ:

class SomeType 
{ 
    InnerType val; 
public: 
    SomeType() : val(...) 
    { 
    throw Exception; 
    } 
}; 

Khi bạn tạo một đối tượng SomeType, nó sẽ gọi InnerType::InnerType. Miễn là nó không ném, sau đó nó sẽ nhập vào constructor của SomeType. Khi đó ném, nó sẽ gây ra val để bị phá hủy, do đó gọi InnerType::~InnerType.

+1

Ah có ý nghĩa ... Nhân tiện, bạn có phải là người đã viết hướng dẫn đồ họa 3D tuyệt vời không? Tôi không thể cảm ơn bạn đủ hướng dẫn đó. – newprogrammer

+3

"Điều này sẽ gây ra destructor của tất cả các thành viên của nó được gọi, nhưng không phải là destructor riêng của nó." - Vâng, chỉ những người đã hoàn thành xây dựng trước khi ngoại lệ được ném .... –

2

Hai câu lệnh này không mâu thuẫn nhau, nhưng câu đầu tiên có một số ngôn ngữ không may. Khi xây dựng một số đối tượng ném, nó deconstructor sẽ không được gọi, nhưng tất cả các đối tượng thuộc sở hữu của đối tượng đó sẽ bị phá hủy bởi deconstructors cá nhân của họ.

Vì vậy, với RAII và con trỏ thông minh các trình phá hủy cho bất kỳ thành viên con trỏ nào của một đối tượng sẽ được gọi độc lập với hàm hủy của đối tượng owing. Con trỏ thô không giải phóng bộ nhớ mà chúng trỏ đến và phải xóa thủ công. Nên các nhà xây dựng của đối tượng sở hữu ném con trỏ nguyên sẽ không được giải phóng. Điều này không thể xảy ra với con trỏ thông minh.

5

Không có mâu thuẫn nào ở đây; chỉ có một số thuật ngữ khó hiểu được sử dụng trong các ngữ cảnh khác nhau.

Nếu constructor của một đối tượng ném một ngoại lệ, sau đó sau đây xảy ra (giả sử các ngoại lệ được bắt):

  1. Tất cả các biến cục bộ trong các nhà xây dựng đã destructors họ gọi, giải phóng mọi nguồn lực mà họ đã mua (nếu bất kì).
  2. Tất cả các subobject trực tiếp của đối tượng mà nhà xây dựng đã ném một ngoại lệ sẽ có destructors của họ được gọi, giải phóng tài nguyên mà họ đã có được (nếu có).
  3. Tất cả các lớp cơ sở của đối tượng mà nhà xây dựng đã ném sẽ có trình phá hủy của chúng được gọi ra (vì chúng được xây dựng hoàn chỉnh trước khi hàm tạo lớp dẫn xuất)
  4. Làm sạch thêm từ người gọi v.v.

Do vậy, bất kỳ tài nguyên được quản lý bởi con trỏ thông minh hoặc đối tượng RAII khác mà thành viên dữ liệu của đối tượng được destructed thực sự sẽ được dọn dẹp, nhưng mã chuyên ngành để làm dọn dẹp trong destructor của đối tượng thắng lửa.

Hy vọng điều này sẽ hữu ích!

+0

Có mô tả từng bước của bạn xóa tất cả mọi thứ! – newprogrammer

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