У меня был класс .NET, который не был реализован IComparable
интерфейс.
После того, как я реализовал IComparable
В интерфейсе этого класса некоторый код на С ++, использующий мой класс, неожиданно изменил свое поведение. Теперь это бросает 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;
}
Проблема была в линии if (nullptr == unitNames[i])
который начал использовать IComparable
реализация для выполнения ==
работа!
Причиной был шаблон от cliext
служебный заголовочный файл.
//
// 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);
}
Вопрос 1: Я не эксперт по С ++, поэтому кто-то может объяснить мне, почему эта реализация не выполняет нулевую проверку _Left
перед звонком CompareTo()
метод? В соответствии с Рекомендации MSDN по перегрузке Equals () и 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;
}
...
Вопрос 2: Есть ли какой-то недостаток в использовании, который приводит к такому непредсказуемому поведению?
поэтому кто-то может объяснить мне, почему эта реализация не выполняет нулевую проверку _Left перед вызовом метода CompareTo ()
Потому что тот, кто написал это, пренебрегал проверкой на нулевые значения.
Есть ли какой-то недостаток в использовании, который приводит к такому непредсказуемому поведению?
Что ж, сравнение нулевого указателя с чем-то, вероятно, является крайним случаем, но я бы не назвал это «недостатком». Реализация ==
это неверно.
Чтобы обойти эту проблему, вы можете отменить проверку на равенство и / или проверить null
:
if (unitNames[i] == nullptr)
dwRet = BUMC_NOT_COMPLETE;
Других решений пока нет …