2016-07-19 2 views
-1

네이티브 C++ 응용 프로그램에서 작업 중이며 별도 어셈블리의 일부 관리 클래스를 사용하여 C#에서 원래 개발 된 데이터 컨테이너를 읽고 쓰려고합니다. interop 계층은 기본적으로 데이터를로드 한 다음 관리되는 데이터를 응용 프로그램에서 사용할 수 있도록 기능적으로 동일한 기본 데이터 컨테이너로 미러링합니다.C++/CLI System.NullReferenceException이 네이티브 코드에서 throw 됨

정직하게 말하자면,이 상호 운용성을 시도하는 것은 아주 재미있는 일이 아니지만, 대부분이 시점에서 작동합니다. 모든 것을 가지고있는 번역 단계가 있지만 디버깅하는 동안 관리되는 예외 (System.NullReferenceException)가 네이티브 C++에서만 발생합니다. 나는 이것이 왜 일어나는 지 전혀 이해하지 못하고 있으며, 누군가가 무슨 일이 일어나고 있는지 이해할 수 있기를 바라고 있습니다. 난 ... 그것은 던지고 위치에있는 스택의 관리 부분에 수를 예상하지 않았을

이것은 우리의 코드가 무엇을하고 있는지의 버전을 박탈입니다 :

// The native data types. 
class cUnmanagedInterpolator 
{ 
    virtual std::vector<std::pair<double, cUnmanagedInterpolator>& GetPoints() { return mPoints; } 
    std::vector<std::pair<double, cUnmanagedInterpolator> mPoints; 
}; 

class cUnmanagedInterpolator_Const : public cUnmanagedInterpolator 
{ 
    virtual double GetValue() const { return mValue; } 
    double mValue 
}; 

// The managed data types (please forgive syntax errors here; they're actually written in C# in our software, and this is just to get the point across). 
class ManagedInterpolator 
{ 
    property List<KeyValuePair<double, ManagedInterpolator^>^ Points = gcnew List<KeyValuePair<double, ManagedInterpolator^>(); 
}; 

class ManagedInterpolator_Const : public ManagedInterpolator 
{ 
    property double DependentValue; 
}; 

// The function to mirror the managed data container into a native counterpart. 
void CopyManagedPoints(ManagedInterpolator^ rhManagedInterpolator, cUnmanagedInterpolator* pUnmanagedInterpolator) 
{ 
    // Go through each managed point in the interpolator and add a corresponding unmanaged one. 
    for each(auto point in rhManagedContainer->Points) 
    { 
     // If this is a constant interpolator, just copy the values. 
     if(dynamic_cast<ManagedInterpolator_Const^>(point->Value) != nullptr) 
     { 
      // Create a new unmanaged copy of the point. 
      // I even tried making x and r pointers and allocating the doubles on the heap with "new" to make sure they weren't somehow ending up as CLI types, but it didn't make a difference. 
      double x = point->Key; 
      double r = dynamic_cast<ManagedInterpolator_Const^>(point->Value)->DependentValue; 
      std::pair<double, cUnmanagedInterpolator> newPoint(x, cUnmanagedInterpolator_Const(r)); 

      // The unmanaged point data was looking weird, and this appeared to be where it was happening, so create a message with what it thinks the point is at this point. 
      // ***The next line is where the System.NullReferenceException is thrown.*** 
      std::string debugMessage = MakeString(newPoint.first) + ", " + MakeString(dynamic_cast<cUnmanagedInterpolator_Const*>(&(newPoint.second))->GetValue()); 

      // Add the copy to the unmanaged interpolator. 
      pUnmanagedInterpolator->GetPoints().push_back(newPoint); 

      // ***Trying to reference the newly created point by using pUnmanagedInterpolator->GetPoints().back() also results in an exception. 

      // Show the debug message to the user. 
      AfxMessageBox(debugMessage.c_str()); 
     } 
     // Otherwise, add a new base class interpolator. 
     else 
     { 
      cUnmanagedInterpolator* pNewInterp = new cUnmanagedInterpolator(); 

      // Recurse as deep as it goes. 
      if(pNewInterp) 
      { 
       pUnmanagedInterpolator->GetPoints().push_back(std::make_pair(point->Key, std::move(*pNewInterp))); 
       CopyManagedPoints(point->Value, &(pUnmanagedInterpolator->GetPoints().back().second)); 
       delete pNewInterp; 
       pNewInterp = nullptr; 
      } 
     } 
    } 
} 

// Roughly how the function would be used. 
int main() 
{ 
    ManagedInterpolator^ rhManagedInterpolator = gcnew ManagedInterpolator(/*initialization information*/); 

    cUnmanagedInterpolator* pNewInterp = new cUnmanagedInterpolator(); 

    CopyManagedPoints(rhManagedInterpolator, pNewInterp); 

    // Use the data... 

    return 0; 
} 

예외는 내부 if 문에서 발생합니다 (문제가 발생한 것으로 보이는 3 개의 별표 ("***") 앞에 주석이 있습니다).

충분히 분명하지 않다 경우 코드의 빠른 요약 :

기본적으로, 데이터 컨테이너가 독립 및 종속 값 ("포인트")의 쌍을 포함하는 "보간"입니다. 종속 값은 다른 보간 자 또는 스. 라 값일 수 있습니다. 인터폴 레이터 인 종속 값은 원하는만큼 반복 될 수 있지만 인터폴 레이터에서 파생 된 클래스 인 고정 값으로 끝나야합니다.

답변

1

네이티브 코드가 아니므로 핸들 (^)을 사용하고 있습니다. 문제는 귀하의 쌍 newPointNullReferenceException을 생성하는 행에서 에서 cUnmanagedInterpolator_Const으로 시도하는 두 번째 값으로 cUnmanagedInterpolator 개체를 가지고 있다는 것입니다. 이 캐스트는 실패하고 nullptr을 반환합니다.이 경우 참조를 해제하면 예외가 발생합니다. 당신이 쌍을 만들 때 기본적으로

, 당신이 cUnmanagedInterpolator_Const 시작하면서, 그것이 cUnmanagedInterpolator_Const으로서의 정체성을 상실하고 cUnmanagedInterpolator되고하는 cUnmanagedInterpolator을 분리합니다.

+0

아아 ... 물론 가치에 의해 전달 될 때 (더 구체적으로, 복사 생성자가 [this answer] (http://stackoverflow.com/a/8278824/6114796))라고 불리는 경우 다형성을 유지하지 않습니다. 아마 이것은 또한 생성자 이동에도 적용됩니까?) ... 나는 정말 어리 석다. 아마도 C++ 101 일 것 같습니다. 어쨌든, 네이티브 객체에 액세스 할 때 CLR 예외가 발생하는 이유는 무엇입니까 (전체 행은 기본 구조 만 사용합니다)? 대신 C++ 또는 SEH 예외 (또는 아마도 거기에없는 함수 주소에 대한 액세스 위반)를 던지면 안됩니까? – BoatsBoatsBoats

+1

'/ clr' 옵션을 사용하여 컴파일하면 네이티브 코드가 생성되지 않습니다. – 1201ProgramAlarm

+0

@BoatsBoatsBoats : AFAIK, SEH 예외를 throw하고 처리기 체인 어딘가의 NullReferenceException으로 변환됩니다 (코드가 먼저 처리하지 않는 경우에만 가능). 네이티브 함수를 호출 할 때 그 번역을 사용하지 못하도록하는 곳이없는 것 같습니다. 특히 "마지막"가능 핸들러에서 발생하면 처리되지 않은 SEH 예외를 변환합니다. – Medinoc

관련 문제