C++ C++;std::equal——不测试大小相同的两个量程的基本原理?

C++ C++;std::equal——不测试大小相同的两个量程的基本原理?,c++,stl,C++,Stl,我只是写了一些代码来测试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 equ

我只是写了一些代码来测试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();
  }  
}
观察:为什么不先检查两个容器的大小是否相同()?有正当理由吗

观察:为什么std::equal不首先检查两个容器的大小是否相同()?有正当理由吗


怎么做?您不向函数传递容器,而是传递迭代器。函数无法知道第二个容器的大小。它所能做的就是假定用户真正传入了两个有效的容器范围(即,第二个范围被正确指定为半开间隔[
lst2.begin()
lst2.begin()
-
lst1.begin()
+
lst1.end()
[)然后相应地行动。

它给了你正确的答案-你让它检查两个容器在
lst1.begin()
lst1.end()
的范围内是否相等。就
equal()
而言,你仍然在比较两个空列表。如果你将代码更改为从
lst2.begin()进行比较
lst2.end()
,您将得到您期望的结果。

因为检查大小可能是一个
O(n)
操作。

您始终可以编写自己的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);
}
模板
布尔等式(先输入计数器1,后输入计数器1,
输入过滤器2优先2,输入过滤器2最后2)
{
而((first1!=last1)&(first2!=last2))
{
if(*first1!=*first2)//或:if(!pred(*first1,*first2)),用于pred版本
返回false;
++first1;++first2;
}
返回(first1==last1)&(first2==last2);
}

为了确保两个范围具有相同数量的元素,签名必须包括第二个范围的结尾。

C++14添加了一个四参数重载,与R Samuel Klatchko的答案中的重载非常相似。并且至少我检查了两个STL实现(libc++和MSVC)对随机访问迭代器执行明显的距离检查前优化。< /P>列表大小的检查不是固定的时间-必须迭代列表。@尼尔:它可能有固定的时间。微软实现具有恒定的时间<代码> siz()/<代码>。在容器要求中,C++标准只表示<代码>大小。()应该具有恒定的时间复杂度。GCC实现具有线性时间
size()
。有关为什么
std::list()
可能具有或可能不具有恒定复杂度的讨论,请参阅。事实证明,最新的C++0x草案要求
size()
具有恒定的时间复杂度(对容器要求的更改是在N3000中进行的)。@Michael:谢谢你的链接。你说得对,康拉德。我忘了我正在将迭代器传递给std::equal。话虽如此,是否有类似于STL提供的:equal(lst1,lst2)的功能?@ShaChris32:是的,你可以比较两个列表(或者通常是两个相同类型的标准容器)使用
=
。在我看来,它与迭代器而不是容器一起工作是STL最大的优点之一。@James:这个想法是将算法从容器中分离出来,迭代器做得很好。也就是说,Alexandrescu最近有一次演讲,名为“迭代器必须离开”这建议使用范围而不是迭代器。我同意他的观点。@Mike:如果我没有弄错的话,容器和迭代器范围都可以作为范围(您可以创建一个迭代器范围对象,存储这两个迭代器,并通过相同的
begin()
end()
方法访问它们)。它在boost中使用,非常方便。不。没有可移植的方法来知道第二个容器的大小。这些信息对于
equals
,无论是直接的还是间接的,都是不可用的。@Konrad:当然有:只需从头到尾迭代两个列表并计算元素的数量。@John:你是如何得到这个结果的列表2的结束迭代器?我当然不知道。我不知道我在想什么。第二个范围甚至不需要大小。例如,你有一个生成随机数的输入迭代器,你想将列表中的一组值与这些值的序列进行比较(不要问我为什么)。
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);
}