Câu hỏi: Tại sao Java / C # không thể triển khai RAII?
Làm rõ: Tôi biết rằng trình thu gom rác không mang tính quyết định. Vì vậy, với các tính năng ngôn ngữ hiện tại, phương thức Dispose () của đối tượng không thể được gọi tự động khi thoát khỏi phạm vi. Nhưng một tính năng xác định như vậy có thể được thêm vào?
Sự hiểu biết của tôi:
Tôi cảm thấy việc triển khai RAII phải đáp ứng hai yêu cầu:
1. Tuổi thọ của tài nguyên phải được ràng buộc trong một phạm vi.
2. Ngấm ngầm. Việc giải phóng tài nguyên phải xảy ra mà không có tuyên bố rõ ràng của lập trình viên. Tương tự như một bộ nhớ giải phóng bộ nhớ rác mà không có một tuyên bố rõ ràng. "Nhân chứng" chỉ cần xảy ra tại điểm sử dụng của lớp. Tất nhiên, người tạo thư viện lớp phải thực hiện rõ ràng một phương thức hàm hủy hoặc Dispose ().
Java / C # thỏa mãn điểm 1. Trong C #, một tài nguyên triển khai IDis có thể được liên kết với phạm vi "sử dụng":
void test()
{
using(Resource r = new Resource())
{
r.foo();
}//resource released on scope exit
}
Điều này không thỏa mãn điểm 2. Lập trình viên phải ràng buộc rõ ràng đối tượng vào một phạm vi "sử dụng" đặc biệt. Các lập trình viên có thể (và làm) quên kết nối tài nguyên một cách rõ ràng với một phạm vi, tạo ra sự rò rỉ.
Trong thực tế, các khối "bằng cách sử dụng" được trình biên dịch chuyển thành mã try-cuối-dispose (). Nó có cùng bản chất rõ ràng của mẫu thử-cuối cùng-dispose (). Không có một bản phát hành ngầm, móc vào một phạm vi là cú pháp đường.
void test()
{
//Programmer forgot (or was not aware of the need) to explicitly
//bind Resource to a scope.
Resource r = new Resource();
r.foo();
}//resource leaked!!!
Tôi nghĩ rằng đáng để tạo một tính năng ngôn ngữ trong Java / C # cho phép các đối tượng đặc biệt được nối với ngăn xếp thông qua một con trỏ thông minh. Tính năng này sẽ cho phép bạn gắn cờ một lớp là giới hạn phạm vi, để nó luôn được tạo bằng một móc vào ngăn xếp. Có thể có các tùy chọn cho các loại con trỏ thông minh khác nhau.
class Resource - ScopeBound
{
/* class details */
void Dispose()
{
//free resource
}
}
void test()
{
//class Resource was flagged as ScopeBound so the tie to the stack is implicit.
Resource r = new Resource(); //r is a smart-pointer
r.foo();
}//resource released on scope exit.
Tôi nghĩ rằng nhân chứng là "đáng giá". Giống như nhân chứng của việc thu gom rác là "đáng giá". Sử dụng các khối rõ ràng đang làm mới trên mắt, nhưng không cung cấp lợi thế về ngữ nghĩa so với thử-cuối-xử lý ().
Có phải là không thực tế khi triển khai một tính năng như vậy vào các ngôn ngữ Java / C # không? Nó có thể được giới thiệu mà không phá vỡ mã cũ?
using
thực hiện Dispose
được đảm bảo (tốt, giảm giá quá trình đột ngột chết mà không có ngoại lệ được ném, tại thời điểm đó, tất cả các hoạt động dọn dẹp có lẽ sẽ trở thành tranh luận).
struct
), nhưng chúng thường được tránh ngoại trừ trong các trường hợp rất đặc biệt. Xem thêm .
Dispose
s được bao giờ chạy, bất kể như thế nào họ đang kích hoạt. Thêm phá hủy ngầm ở cuối phạm vi sẽ không giúp điều đó.