네이티브 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 개의 별표 ("***") 앞에 주석이 있습니다).
충분히 분명하지 않다 경우 코드의 빠른 요약 :
기본적으로, 데이터 컨테이너가 독립 및 종속 값 ("포인트")의 쌍을 포함하는 "보간"입니다. 종속 값은 다른 보간 자 또는 스. 라 값일 수 있습니다. 인터폴 레이터 인 종속 값은 원하는만큼 반복 될 수 있지만 인터폴 레이터에서 파생 된 클래스 인 고정 값으로 끝나야합니다.
아아 ... 물론 가치에 의해 전달 될 때 (더 구체적으로, 복사 생성자가 [this answer] (http://stackoverflow.com/a/8278824/6114796))라고 불리는 경우 다형성을 유지하지 않습니다. 아마 이것은 또한 생성자 이동에도 적용됩니까?) ... 나는 정말 어리 석다. 아마도 C++ 101 일 것 같습니다. 어쨌든, 네이티브 객체에 액세스 할 때 CLR 예외가 발생하는 이유는 무엇입니까 (전체 행은 기본 구조 만 사용합니다)? 대신 C++ 또는 SEH 예외 (또는 아마도 거기에없는 함수 주소에 대한 액세스 위반)를 던지면 안됩니까? – BoatsBoatsBoats
'/ clr' 옵션을 사용하여 컴파일하면 네이티브 코드가 생성되지 않습니다. – 1201ProgramAlarm
@BoatsBoatsBoats : AFAIK, SEH 예외를 throw하고 처리기 체인 어딘가의 NullReferenceException으로 변환됩니다 (코드가 먼저 처리하지 않는 경우에만 가능). 네이티브 함수를 호출 할 때 그 번역을 사용하지 못하도록하는 곳이없는 것 같습니다. 특히 "마지막"가능 핸들러에서 발생하면 처리되지 않은 SEH 예외를 변환합니다. – Medinoc