2010-05-26 4 views
1

상당히 특수한 문제가 있습니다. 며칠 동안 고민하고 있습니다.관리되는 클래스의 관리되지 않는 구조 인스턴스

저는 네이티브 C++을 사용하고 있습니다. 메소드 중 하나는 고정 크기 char 배열을 포함하는 구조체에 ptr을 사용합니다.

struct userData { 
    char data1[10]; 
    char data2[10]; 
}; 

방법 :

short AddItem(long id, userData* data); 

내가 관리 VC에서이 전화를 호출하기 위해 노력하고있어 ++하지만 난 내 관리되는 클래스에의 보류를 유지할 수 userData에의 인스턴스가 필요합니다.

누구든지이 작업을 수행하는 방법을 도울 수 있습니까?

감사

관리 클래스의 데이터에 대한 포인터는 소멸자에서 삭제

답변

3

나는 다음과 같은 두 개의 컨테이너 중 하나를 사용하십시오.

ref class MyManagedClass { 
    GcPlainPtr<userData> myUserData; 

    MyManagedClass(...bla...) 
     : myUserData(new userData(...)) 
     , ... 
    {...} 

    AnotherMethod() { 
     std::cout << myUserData->data1 << '\n'; 
     AddItem(1, myUserData.get()); 
    } 
} 

이전 방식의 장점은 당신이 개체를 삭제하는 것을 잊지 경우에도 그 가비지 콜렉션이 해당 주파수에서 발생하므로, 메모리 압력이 합리적으로 업데이트 될 것입니다 : 다음과 같이 사용할 수 있습니다. 당신이 roughtly 할당하고있는 데이터 요소의 크기를 알고 있지만 그것은 단지 직접 크기가 아니다 (기본 구조체 즉, 또는 클래스가 내부적으로 메모리를 할당) 경우

, 다음과 같은 변형이 더 적합 할 수 있습니다

template<typename T> ref class GcAutoPtr sealed { 
    T* ptr; 
    size_t size; 
public: 
    GcAutoPtr(T*ptr,size_t size) : ptr(ptr), size(size) { 
     GC::AddMemoryPressure(size); 
    } 

    !GcAutoPtr() { 
     GC::RemoveMemoryPressure(size); 
     size=0; 
     delete ptr; 
     ptr = nullptr; 
    } 

    ~GcAutoPtr() { this->!GcAutoPtr();} //mostly just to avoid C4461 

    T* get() {return ptr;} 

    static T* operator->(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr;} 
    static operator T*(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr; } 
}; 
0

스토어.

template<typename T> ref class GcPlainPtr sealed { 
    T* ptr; 
public: 
    GcPlainPtr(T*ptr): ptr(ptr) { GC::AddMemoryPressure(sizeof(T)); } 

    !GcPlainPtr() { 
     GC::RemoveMemoryPressure(sizeof(T)); 
     delete ptr; ptr = nullptr; 
    } 

    ~GcPlainPtr() { this->!GcPlainPtr(); } //mostly just to avoid C4461 

    T* get() {return ptr;} 

    static T* operator->(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr;} 
    static operator T*(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr; } 
}; 

이전 컨테이너가 사용자의 요구에 충분한 같습니다 가비지 컬렉션 친화적 인 상호 운용성을 선호한다면

ref class MyManagedClass 
{ 
    userData *myUserData; 

public: 
    ~MyManagedClass() 
    { 
     if (myUserData) 
      delete myUserData; 
     myUserData = NULL; 
    } 

    short AddItem(long id, userData* data) 
    { 
     if (myUserData) 
      delete myUserData; 
     myUserData = new userData(*data); 
    } 
} 
1

관리되는 클래스 개체에 인스턴스를 저장하고 쉽게 포인터를 생성 할 수 없습니다. 그건 가비지 컬렉터와 매우 호환되지 않습니다. 예측할 수없는 시간에 발생할 수있는 힙을 압축 할 때 관리 대상 객체를 이동시킵니다. userData 멤버에 대한 포인터를 전달하려고하면 컴파일러 오류가 발생합니다.

일부 해결 방법 : 힙에 userData 인스턴스를 new로 할당하고 관리 객체에 포인터를 저장하십시오. 꽤 비효율적이지만, 소멸자와 파이널 라이저를 구현해야합니다. 관리되는 클래스의 인스턴스 수가 제한 될 것으로 예상하는 경우에만이 작업을 수행하십시오.

다음 해결책은 호출시 포인터를 생성하는 것입니다 (pin_ptr <>). 이는 관리 객체를 메모리에 고정시켜 가비지 컬렉터가 이동하지 못하게합니다. 물론 굉장히 효율적인 것은 아닙니다.

마지막으로 userData 인스턴스를 호출하여 호출하는 메소드에서 userData의 인스턴스를 로컬 변수로 선언하여 관리 대상 객체의 인스턴스로 호출 할 수 있습니다. 스택 변수에 대한 포인터를 생성하는 데 아무런 문제가 없으며 이동할 수 없습니다. 이제 관리 클래스의 구조를 자유롭게 선언 할 수 있습니다. 이 구조체가 너무 크지 않다고 가정하면 그것이 내가 선택할 것입니다.

관련 문제