2010-09-10 31 views
6

Tôi đã quen với các cơ sở C++ RAII và tôi muốn sử dụng RAII đúng cách với mã được quản lý trong C++/CLI. HerbSutterMicrosoft cả hai đều cho tôi biết đây là phương pháp hay nhất.RAII trong C++/CLI

Tôi có một cái gì đó như thế này:

ref struct Managed 
{ 
    // No default constructor 
    Managed(/*...*/) { /*...*/ } 
    ~Managed() { /* Important non-managed resource release here */ } 
    // ... 
}; 

ref struct UsesManaged 
{ 
    Managed^   m_; 
    array<Managed^>^ a_; 

    UsesManaged(Managed^ m, array<Managed^>^ a) : m_(m), a_(a) {} 
    // ... 
}; 

ref struct Creator 
{ 
    Managed^   m_; 
    array<Managed^>^ a_; 
    UsesManaged^  u_; 

    Creator() 
    { 
     // Must allocate dynamically here, not in initializer list 
     // because in my real code, I use "this" here for a callback. 
     m_  = gcnew Managed(/*...*/); 
     a_  = gcnew array<Managed^>(2); 
     a_[ 0 ] = gcnew Managed(/*...*/); 
     a_[ 1 ] = gcnew Managed(/*...*/); 
     u_  = gcnew UsesManaged(m_, a_); 
    } 
}; 

Tôi muốn (1) phá hủy tài nguyên tự động vì vậy tôi không cần phải xóa tất cả các đối tượng gcnew'ed bằng tay, đặc biệt là khi đối mặt với trường hợp ngoại lệ; (2) khả năng chia sẻ các đối tượng một cách an toàn và rõ ràng (đi qua xung quanh std :: auto_ptr và những thứ tương tự không đủ điều kiện); và (3) khả năng để lớp của tôi được tiêu thụ bởi VB hoặc C# và việc dọn dẹp tự động chạy khi đối tượng nằm ngoài phạm vi (ví dụ, do một ngoại lệ).

Trong tiêu chuẩn C++ tôi muốn sử dụng tiêu chuẩn :: shared_ptr và std :: vector hoặc các cơ sở tương tự để tự động hóa RAII. Ở đây, tôi có thể sử dụng vector của STL/CLI, nhưng không có shared_ptr tương đương. Con trỏ thông minh C++/CLI liên quan duy nhất tôi thấy là sparsely documented msclr::auto_handle, tương tự như std :: auto_ptr, bao gồm cả ngữ nghĩa chuyển giao quyền sở hữu, không tương thích với vectơ, mặc dù chúng hoạt động ổn định trong một mảng.

Cách C++/CLI phù hợp để đạt được ba mục tiêu của tôi là gì? (Cũng lưu ý, lớp C++/CLI chính của tôi, Trình tạo ở trên, sẽ được tiêu thụ bởi VB/C#.)

[Cập nhật: Thêm liên kết vào Herb Sutter và MS ở trên cùng và thêm mục tiêu 3 (tiêu thụ bởi VB/C#)]

+0

Nói đúng, đây không phải là RAII bởi vì bạn đang sử dụng bài tập, chứ không phải khởi tạo, để sở hữu tài nguyên. Nó là một con trỏ thông minh chia sẻ rất nhiều với RAII. –

+0

Giao diện IDisposable là một mẫu được thiết lập tốt trong mã được quản lý. Nhưng bạn * thực sự * cũng phải bao gồm trình hoàn thiện để giải phóng tài nguyên được thực hiện tự động. Thêm! Được quản lý(). –

+0

Hans, tôi nghĩ bạn có thể đã xóa câu trả lời dài hơn về điều này. Nó rất hữu ích, và tôi ước bạn đã rời khỏi nó để chúng tôi có thể thảo luận ở đó. – metal

Trả lời

1

Tôi lấy câu trả lời đúng cho câu hỏi của tôi là Billy ONeal 's bình luận về một người nào đó câu trả lời khác:

Ah - bạn không thể làm điều đó. Không có cách nào để buộc bộ thu gom rác đến phá hủy một đối tượng. Xem blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx Cách đúng để thực hiện điều đó là yêu cầu cuộc gọi gần rõ ràng và để thực hiện cuộc gọi với điều đó trong trình kết thúc. Nếu vì một số lý do mã khách hàng không làm sạch, GC sẽ (cuối cùng) dọn dẹp cho bạn (tại chương trình chấm dứt nếu không có gì khác), nhưng bạn không thể viết mã phụ thuộc vào . - Billy Oneal 10 Tháng 9 '10 tại 16:02

Bên cạnh những liên kết mang đến cho anh, thấy cũng herehere.

1

bạn có thể có RAII với mã số quản lý:. nếu bạn có điều này:

ref class A { 
    ~A() { // implements/overrides the IDisposable::Dispose method 
     // free managed and unmanaged resources here 
    } 
}; 


Sau đó, bạn có thể làm điều này:

void foo() 
{ 
    A a(cons_args); // stack-like usage 
    // use a ... 
} 

và điều này một cách hiệu quả sẽ được coi như:

void foo() 
{ 
    try 
    { 
    A^ a_ = gcnew A(cons_args); 
    } 
    finally 
    { 
    a_->~A(); 
    } 
} 
+0

+1, yup, đây là cách để làm điều đó. Tôi không thích cú pháp mãnh liệt, đó là một trình tạo lỗi lớn và cung cấp cho những người mới rất ít cơ hội đoán được khi họ phải sử dụng dấu mũ. Nhưng cũng vậy. –

+0

+1 - nhưng tôi vẫn nghĩ rằng bất cứ ai làm điều này cần phải đọc http://msdn.microsoft.com/en-us/library/ms177197.aspx –

+0

Phải, nhưng như tôi đã gợi ý trong nhận xét trong hàm tạo của Người tạo, tôi phải sử dụng phân bổ động hơn là phân bổ "ngăn xếp GC". Những gì tôi thực sự cần là một C++/CLI tương đương với std :: shared_ptr. – metal

1

Không thử nghiệm, nhưng điều này sẽ giúp bạn bắt đầu:

template<typename T> 
value class counted_handle 
{ 
    ref struct Count { int refCount; Count() : refCount(1) {} }; 
    T^ m_sharedHandle; 
    Count^ m_sharedCount; 

    void release() { if (m_sharedCount && 0 == --sharedCount->refCount) delete m_sharedHandle; m_sharedCount = nullptr; m_sharedHandle = nullptr; } 
    void addref(if (m_sharedCount) ++m_sharedCount->refCount; } 
public: 
    counted_handle() : m_sharedHandle(nullptr), m_sharedCount(nullptr) {} 
    counted_handle(T^ handle) : m_sharedHandle(handle), m_sharedCount(gcnew Count()) {} 
    counted_handle(counted_handle<T>% src) : m_sharedHandle(src.m_sharedHandle), m_sharedCount(src.sharedCount) { addref(); } 
    void ~counted_handle() { release(); } 
    counted_handle<T>% operator=(counted_handle<T>% src) { src.addref(); release(); m_sharedHandle = src.m_sharedHandle; m_sharedCount = src.m_sharedCount; } 
    counted_handle<T>% operator=(T^ handle) { release(); m_sharedHandle = handle; m_sharedCount = gcnew Count(); } 
} 
Các vấn đề liên quan