RAII là gì? Ví dụ?


19

Luôn luôn khi thuật ngữ RAII được sử dụng, mọi người thực sự đang nói về giải cấu trúc thay vì khởi tạo. Tôi nghĩ rằng tôi có một sự hiểu biết cơ bản về ý nghĩa của nó nhưng tôi không chắc lắm. Ngoài ra: C ++ có phải là ngôn ngữ RAII duy nhất không? Còn Java hay C # /. NET thì sao?

Câu trả lời:


25

Thu thập tài nguyên là khởi tạo có nghĩa là các đối tượng nên tự chăm sóc bản thân như một gói hoàn chỉnh và không mong đợi mã khác sẽ nói với một ví dụ "này nhân tiện, bạn sẽ sớm được dọn dẹp - hãy dọn dẹp ngay bây giờ." Nó thường có nghĩa là có một cái gì đó có ý nghĩa trong hàm hủy. Điều đó cũng có nghĩa là bạn viết một lớp đặc biệt để quản lý tài nguyên, biết rằng trong một số trường hợp khó dự đoán nhất định, như ngoại lệ bị ném, bạn có thể tin tưởng vào việc thực thi lệnh hủy diệt.

Giả sử bạn muốn viết một số mã nơi bạn sẽ thay đổi con trỏ cửa sổ thành con trỏ chờ (đồng hồ cát, bánh rán không hoạt động, v.v.), làm công cụ của bạn và sau đó thay đổi lại. Và cũng nói rằng "làm công cụ của bạn" có thể ném một ngoại lệ. Cách làm của RAII sẽ là tạo ra một lớp mà ctor đặt con trỏ chờ, phương thức "thực" của bạn đã làm bất cứ điều gì bạn muốn và dtor đặt lại con trỏ. Tài nguyên (trong trường hợp này là trạng thái con trỏ) được gắn với phạm vi của một đối tượng. Khi bạn có được tài nguyên, bạn khởi tạo một đối tượng. Bạn có thể tin tưởng vào đối tượng bị phá hủy nếu ngoại lệ bị ném và điều đó có nghĩa là bạn có thể tin tưởng vào việc dọn dẹp tài nguyên.

Sử dụng RAII tốt có nghĩa là bạn không cần finally. Tất nhiên, nó dựa vào sự hủy diệt xác định mà bạn không thể có trong Java. Bạn có thể nhận được một loại hủy xác định trong C # và VB.NET với using.


4
Tôi nghĩ rằng đây là những gì bạn đang làm, nhưng bạn có thể muốn thêm rằng lý do tại sao Java và C # không hỗ trợ RAII là vì trình thu gom rác. Trong C ++, một đối tượng cục bộ sẽ bị hủy ngay khi nó ra khỏi phạm vi. Trong Java / C #, điều này không đúng.
Jason Baker

Mở rộng trên điểm Jasons, lý do tại sao Java và C # không thể đảm bảo phá hủy kịp thời là do khả năng của các chu kỳ tham chiếu, điều đó có nghĩa là không thể xác định một trật tự an toàn để chạy các hàm hủy. Các chu trình tham chiếu cũng có thể xảy ra trong C ++, nhưng các hàm ý khác nhau - lập trình viên chịu trách nhiệm xác định thứ tự hủy và thực hiện xóa rõ ràng. Trách nhiệm đó thường được đóng gói trong một số hàm hủy của các lớp cấp cao hơn - ví dụ: một lớp container chịu trách nhiệm đảm bảo tất cả các mục chứa trong đó bị hủy. "Quyền sở hữu" là chìa khóa.
Steve314

1
@Jason đó là những gì tôi có nghĩa là "phá hủy xác định" - một lập trình viên C ++ biết khi nào hàm hủy sẽ chạy.
Kate Gregory

Tôi biết đây là một câu trả lời cũ, nhưng tôi vẫn hơi bối rối. Tôi mới biết về thuật ngữ này và một số thông tin nói rằng việc mua lại sẽ xảy ra trong hàm tạo. Điều đó không thực sự có ý nghĩa với tôi và câu trả lời này dường như mâu thuẫn với nó, nhưng bạn có thể làm rõ không?
Per Johansson

1
@PerJohansson Vâng, bạn có được trong ctor. Và bạn phát hành trong dtor. Tôi đã tập trung vào điểm thứ hai, nhưng họ đi cùng nhau. Khi ctor đã hoàn thành, bạn biết bạn có một đối tượng hợp lệ. Và bạn biết rằng bất kể điều gì xảy ra, tài nguyên sẽ được phát hành vào đúng thời điểm.
Kate Gregory

4

RAII là một phần về việc quyết định khi nào một đối tượng chịu trách nhiệm cho việc dọn dẹp của chính nó - quy tắc là đối tượng sẽ chịu trách nhiệm nếu và khi khởi tạo hàm tạo của nó hoàn thành. Sự đối xứng của khởi tạo và dọn dẹp, hàm tạo và hàm hủy, có nghĩa là hai cái này có quan hệ chặt chẽ với nhau.

Một điểm của RAII là đảm bảo an toàn ngoại lệ - ứng dụng vẫn tự đồng nhất khi các ngoại lệ được đưa ra. Thoạt nhìn, điều này là không đáng kể - khi một ngoại lệ khiến phạm vi thoát ra, các biến cục bộ trong phạm vi đó cần phải bị hủy.

Nhưng điều gì xảy ra nếu cú ​​ném ngoại lệ xảy ra trong một hàm tạo?

Chà, vật thể chưa được chế tạo hoàn chỉnh, nên không thể bị phá hủy một cách an toàn. Các nhà xây dựng nên đã thử các khối khi cần thiết để đảm bảo rằng mọi hoạt động dọn dẹp cần thiết đều được thực hiện trước khi ngoại lệ được đưa ra. Khi ngoại lệ di chuyển ra ngoài phạm vi nơi đối tượng được xây dựng, sẽ không có lệnh gọi hàm hủy, vì đối tượng không được xây dựng ở vị trí đầu tiên.

Đặc biệt xem xét các hàm tạo cho dữ liệu thành viên bên trong đối tượng bị phá hủy. Nếu một trong số đó ném ngoại lệ, mã xây dựng chính của bạn sẽ không chạy hoàn toàn - nhưng một số mã tạo thành một phần ngầm định của hàm tạo đó sẽ có. Bất kỳ thành viên nào đã được xây dựng thành công sẽ được tự động hủy. Bất kỳ thành viên nào không được xây dựng (bao gồm cả thành viên đã ném ngoại lệ) sẽ không.

Về cơ bản, RAII là một chính sách đảm bảo rằng mọi thứ được xây dựng hoàn chỉnh sẽ bị phá hủy một cách kịp thời, đặc biệt là khi có các cú ném ngoại lệ, và bất kỳ đối tượng nào cũng được xây dựng hoàn chỉnh hoặc không (không có một nửa các đối tượng được xây dựng mà bạn không thể biết cách dọn dẹp an toàn). Tài nguyên được phân bổ cũng được giải phóng. Và rất nhiều công việc được tự động hóa, vì vậy lập trình viên không phải lo lắng quá nhiều về nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.