I had a .NET class which was not implementing IComparable
interface.
After I implemented IComparable
interface on this class some c++ code using my class changed it's behavior unexpectedly. Now it throws a NullReferenceException
DWORD UnitsAdapter::GetUnitNames([Out]array<MyClass^>^% unitNames)
{
...
unitNames = gcnew array<MyClass^>(10);
DWORD dwRet = BUMC_OK;
for (int i = 0; i < unitNames->Length; ++i)
{
unitNames[i] = nullptr;
unitNames[i] = CoCliUnitsHelper::getUnitName(unitIds[i]);
if (nullptr == unitNames[i])
dwRet = BUMC_NOT_COMPLETE;
}
return dwRet;
}
The problem was in the line if (nullptr == unitNames[i])
which started using IComparable
implementation to perform ==
operation!
The reason was a template from cliext
utility header file.
//
// System::IComparable TEMPLATE COMPARISONS
//
template<typename _Value_t>
bool operator==(System::IComparable<_Value_t>^ _Left,
System::IComparable<_Value_t>^ _Right)
{ // test if _Left == _Right
return (_Left->CompareTo(_Right) == 0);
}
Question 1: I am not a c++ expert, so can someone explain me why this implementation does not perform a null check on _Left
before calling CompareTo()
method ? According to MSDN Guidelines for Overloading Equals() and Operator == null checks must be done prior of doing anything inside ==
operator.
...
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
...
Question 2: Is there probably some flaw in usage which leads to such an unpredictable behavior?