C++ std:: equal - обоснование не тестирования для 2 диапазонов, имеющих одинаковый размер?

Я просто написал код, чтобы проверить поведение std:: equal, и ушел удивленный:

int main()
{
  try
  {
    std::list<int> lst1;
    std::list<int> lst2;

    if(!std::equal(lst1.begin(), lst1.end(), lst2.begin()))
      throw std::logic_error("Error: 2 empty lists should always be equal");

    lst2.push_back(5);

    if(std::equal(lst1.begin(), lst1.end(), lst2.begin()))
      throw std::logic_error("Error: comparing 2 lists where one is not empty should not be equal");
  }
  catch(std::exception& e)
  {
    std::cerr << e.what();
  }  
}

выход (сюрприз для меня):

Error: comparing 2 lists where one is not empty should not be equal

наблюдение: почему это std:: equal сначала не проверяет, имеют ли 2 контейнера одно и то же size() ? Была ли на то законная причина?

5 ответов


замечание: почему std:: equal не проверяет, имеют ли 2 контейнера одинаковый размер() ? Была ли на то законная причина?

как? Вы не передаете контейнеры функции, вы передаете в итераторы. Функция не имеет никакого способа узнать размер второго контейнера. Все, что он может сделать, это предположить, что пользователь прошел в двух допустимых диапазонах контейнеров (т. е. что второй диапазон правильно указан как полуоткрытый интервал [lst2.begin(), lst2.begin() - lst1.begin() + lst1.end()[) и действовать соответственно.


вы всегда можете написать свою собственную версию equal, которая эффективно делает то, что вы хотите:

template <class InputIterator1, class InputIterator2>
bool equalx(InputIterator1 first1, InputIterator1 last1,
            InputIterator2 first2, InputIterator2 last2)
{
  while ((first1 != last1) && (first2 != last2))
  {
    if (*first1 != *first2)   // or: if (!pred(*first1,*first2)), for pred version
      return false;
    ++first1; ++first2;
  }
  return (first1 == last1) && (first2 == last2);
}

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


потому что проверка размера может быть O(n) операции.


Он дает вам правильный ответ-вы сказали ему проверить, равны ли два контейнера в диапазоне lst1.begin() до lst1.end(). Вы все еще сравниваете два пустых списка, насколько это. Если вы измените код для сравнения с lst2.begin() to lst2.end(), вы получите то, что вы ожидали.


в C++14 добавили четыре аргумента перегрузки как в ответ Р Самуэль Klatchko по. И, по крайней мере, две реализации STL, которые я проверил (libc++ и MSVC), реализуют очевидную оптимизацию проверки расстояния для итераторов произвольного доступа.