Is `char * p = 0; std:: equal (p, p, p) `четко определен в соответствии со стандартом С++?

Является ли следующее определение корректным в соответствии со стандартом С++?

char* p = 0;
std::equal(p, p, p);

Вопрос в самом деле:

Требуется ли стандарт, чтобы std::equal(begin1, end1, begin2) реализовывался таким образом, что если begin1 == end1, то begin1 и begin2 может быть любым указателем, даже тем, который не указывает на действительный объект памяти?

Я предполагаю, что это намерение стандарта, но я не смог найти утверждение, которое делает это ясным.

Причина, по которой я беспокоюсь об этом, заключается в том, что VisualStudio, по-видимому, пытается проверить "достоверность" begin2 даже при begin1 == end1. И это противоречит моему пониманию требований стандарта.

EDIT: Вот код от VS 2012, который, я считаю, нарушает стандарт:

template<class _InIt1, class _InIt2> inline
bool equal(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2)
{   // compare [_First1, _Last1) to [First2, ...)
    _DEBUG_RANGE(_First1, _Last1);
    _DEBUG_POINTER(_First2);
    return (_Equal1(_Unchecked(_First1), _Unchecked(_Last1), _First2, _Is_checked(_First2)));
}

template<class _Ty> inline
void _Debug_pointer(const _Ty *_First, _Dbfile_t _File, _Dbline_t _Line)
{   // test iterator for non-singularity, const pointers
    if (_First == 0)
        _DEBUG_ERROR2("invalid null pointer", _File, _Line);
}

Ответ 1

Итак, у нас есть 25.2.1/1, который гласит:

Возвращает: true, если для каждого итератора я в диапазоне [first1, last1) следуя соответствующим условиям: * я == * (first2 + (i - first1)), pred (* i, * (first2 + (i - first1)))!= false.

В противном случае, возвращает false.

В вашем случае нет итераторов в диапазоне [0, 0), поэтому "каждый" итератор в диапазоне проходит тест, но фактический тест не должен выполняться (поскольку в пробеге не существует итераторов).

Он выглядит как ошибка VisualStudio для меня.

Ответ 2

Как отметил @Zac, эта проверка является Visual Studio, являющейся дополнительным педантичным именем безопасности. Если вы хотите, чтобы Visual Studio более точно соответствовала стандарту даже в сборках отладки, вы можете отключить это поведение, установив макрос _ ITERATOR_DEBUG_LEVEL в 0.

Ответ 3

С вашим обновлением ясно, что это не нарушение стандарта, а проверка отладки. Если вы скомпилируете его в режиме Release, эти проверки не запускаются, а функция соответствует стандартным описаниям.

Полезно иметь эту информацию в режиме отладки, так как это поможет вам отследить некоторые трудно найти ошибки.

Ответ 4

Стандартные состояния С++ 11 "[i, i) - пустой диапазон" в 24.2.1/5.

Однако в 24.2.1/5 сначала подразумевается, что 0 должно быть сингулярным значением, а затем означает: "Результаты большинства выражений undefined для сингулярных значений". Затем он перечисляет исключения для поведения undefined, но сравнение не включено.

Так что, возможно, undefined сравнить сингулярные итераторы для равенства, поэтому сделать оценку [i, i) невозможно.

Это также указывает на то, что ваша ошибка во время выполнения происходит внутри функции с именем _Equal1().

Я думаю, что стандарт смутно по отношению к этому, и я совсем не уверен, что это ошибка в Visual Studio 2012.

http://cplusplus.github.io/LWG/lwg-unresolved.html в главе "1213. Значение допустимого и единственного итератора, ограниченного" также довольно забавно с этой путаницей...