Là Hans Passantwishes đây là kịch bản của tôi. Tôi có một ứng dụng chế độ hỗn hợp trong đó mã gốc thực hiện tất cả công việc khó khăn trong khi tôn trọng hiệu suất và mã được quản lý chỉ chịu trách nhiệm đối với GUI. Ngoài ra, người dùng sẽ tham gia bằng cách viết mã C# độc quyền của họ. Tôi có C++ cho các lớp bản địa, C# cho GUI và mã người dùng và C++/Cli cho các lớp bao bọc ở giữa. Trong số tất cả các lớp C++ của tôi có một trong đó có% 90 của các phép tính và được tạo ra một tham số khác nhau mỗi lần. Hãy gọi nó là NativeClass. Có apprx. 2000 phiên bản của lớp NativeClass này và tôi phải tìm đúng cá thể liên quan đến một số tham số trước khi nó tính toán. Vì vậy, tôi nghĩ ra một hash_map, với các tham số là mã băm, cho mục đích này. Khi tôi nhận được một tham số, tôi tìm kiếm một thể hiện đúng trong hash_map, tôi tìm thấy nó và gọi một số phương thức của nó.
Khi người dùng contrubute để tính toán bằng cách viết mã C# và lớp này thực thi các mã này bằng callbacks. Điều này là tầm thường nhưng đôi khi tôi cần một số thông tin về các lớp .Net mà người dùng xây dựng. Vì vậy, tôi cần phải đính kèm cụ thể ManagedClass để NativeClass bằng cách nào đó. Giải pháp đầu tiên của tôi là sử dụng GChandle.Alloc() và chuyển địa chỉ xử lý. Nhưng có một số concerns về GC rằng nó sẽ không được thực hiện công việc của mình đúng cách. Hans đã đề xuất Marshal.AllocCoTaskMem() và Marshal.StructureToPtr() để phân bổ các đối tượng được quản lý trong bộ nhớ không được quản lý, tuy nhiên tôi tin rằng điều này là hợp lệ đối với các lớp hoặc cấu trúc kiểu giá trị. Làm thế nào về các lớp học ref? Làm thế nào tôi có thể vượt qua một tham chiếu đến NativeClass trong khi ngăn chặn chúng được GC thu thập và làm cho GC hoạt động đúng vào thời điểm này?GCHandle, Marshal, bộ nhớ được quản lý và không được quản lý: Để ghim hoặc không ghim
Dưới đây là một số mẫu mã:
class NativeClass
{
private:
int AddressOfManagedHandle;
public:
static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
{
// return NativeClass associated with SomeParameter from NativeClassHashMap;
}
NativeClass(int addr, int SomeParameter) : AddressOfManagedHandle(addr)
{
}
int GetAddress(){return AddressOfManagedHandle;}
void DoCalculation(){
// CALCULATIONS
}
};
public ref class ManagedClass : MarshalByRefObject
{
private:
NativeClass* _nc;
//GCHandle handle;
void FreeManagedClass()
{
Marshal::FreeHGlobal(IntPtr(_nc->GetAddress()));
//if(handle.IsAllocated)
//handle.Free();
delete _nc;
}
public:
ManagedClass()
{
IntPtr addr = (Marshal::AllocHGlobal(Marshal::Sizeof(this))); // Error
Marshal::StructureToPtr(this,addr,true);
//handle = GCHandle.Alloc(this);
//IntPtr addr = handle.ToIntPtr();
_nc = new NativeClass(addr.ToInt32());
}
~ManagedClass() {FreeManagedClass();}
!ManagedClass() {FreeManagedClass();}
int GetAddress() {return _nc->GetAddress();};
static ManagedClass^ GetManagedClass(int SomeParameter)
{
int addr = NativeClass::GetNativeClassFromHashMap(SomeParameter)->GetAddress();
//Object^obj = GCHandle::FromIntPtr(IntPtr(addr)).Target;
Object^ obj = Marshal::PtrToStructure(IntPtr(addr), ManagedClass::typeid);
return dynamic_cast<ManagedClass^>(obj);
}
};
Tôi xin lỗi rằng nó là toooooo dài và vẫn chưa rõ ràng.
Bạn nên sử dụng IntPtr thay vì int để lưu trữ con trỏ gốc. Nếu không, mã của bạn có thể gặp sự cố trên Windows 64 bit. – Elmue
Bạn không nên giải phóng bộ nhớ trong một lớp khác. Viết một hàm hủy (finalizer) ~ NativeClass() gọi FreeHglobal(). – Elmue