22

std::equal() is unsafe because the function cannot know whether it will overrun the length of the second container to be compared. That is:

std::vector< int > v( 100 );
std::vector< int > w( 10 );
bool same = std::equal( v.begin(), v.end(), w.begin() );

...will result in a buffer overrun for w.

Naturally we can test for these things (v.size() == w.size()), but compilers like Visual Studio 2010 still report the function itself as unsafe. And indeed it is unsafe in some fundamental sense: a team of programmers of varying levels of experience will eventually forget to compare sizes.

A safe alternative is easy to implement.

template< typename Iter1, typename Iter2 >
bool equal_safe( Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2 )
{
    while( begin1 != end1 && begin2 != end2 )
    {
        if( *begin1 != *begin2 )
        {
            return false;
        }
        ++begin1;
        ++begin2;
    }
    return begin1 == end1 && begin2 == end2;
}

But is there a safe alternative in the standard library?

OldPeculier
  • 11,049
  • 13
  • 50
  • 76
  • 2
    Safe alternative to do what exactly? Just compare two `std::vector`s? Or two iterator ranges? – Joseph Mansfield May 01 '13 at 20:28
  • @sftrabbit To do what std::equal() does. To compare two iterator ranges. – OldPeculier May 01 '13 at 20:33
  • 1
    It's easy enough to write a safe_equal implementation if == does not satisfy your requirements. – Anon Mail May 01 '13 at 20:35
  • 1
    [_When comparing entire containers for equality, operator== is usually preferred_](http://en.cppreference.com/w/cpp/algorithm/equal) – masoud May 01 '13 at 20:36
  • 8
    I’m not sure I agree with this assessment, even though I understand the complaint: `std::equal` is fundamentally an algorithm working on *iterator ranges* and by its very nature, and like *all* other C++ algorithms on ranges, those ranges are not checked by the algorithm. There is an overwhelming consistency about this point in the standard library, so I think it’s quite hard to make an error about it. You get a uniform interface that behaves completely expectedly. – Konrad Rudolph May 01 '13 at 20:42
  • @KonradRudolph Right, and it's good that if we know what we're doing, we can call the 'unsafe' version, which doesn't have to do 2 x `std::distance()` & hence will perform better for iterators for which distance is slow. However, it is also undeniably good that C++ is adding 'safe' versions taking 2 pairs of iterators, as this supports a wider variety of uses, where sources of iterators aren't always known & it's unnecessary churn to manually check distances. – underscore_d Nov 18 '18 at 21:59

5 Answers5

23

In C++14, the standard library will contain a version of std::equal that takes two pairs of iterators, similar to your safe_equal. Same for std::mismatch and std::is_permutation.

Marshall Clow
  • 15,972
  • 2
  • 29
  • 45
9

vector has an operator== that first checks the size. In your example, just use the condition v==w.

huskerchad
  • 1,026
  • 8
  • 9
  • which means it's safe according to the OP's definition of safe. – Anon Mail May 01 '13 at 20:32
  • Well, I thought it was clear, but for the op's example, "v==w" is safe. – huskerchad May 01 '13 at 20:33
  • @huskerchad I used vectors as an example because it's quick to create two with different sizes. But imagine that one is a list... – OldPeculier May 01 '13 at 20:38
  • 5
    @OldPeculier, I believe all of the STL containers have an operator== that works this way. If your question is whether you can do this for arbitrary iterators, the answer is no, because there is no way to know the length of a sequence based only on a single iterator in the sequence. – huskerchad May 01 '13 at 20:41
1

I have wanted such a feature myself. I have not been able to find any facilities in the standard library.

If you are willing to use boost. Boost.Range has equal which I think is what your are looking for http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/range/reference/algorithms/non_mutating/equal.html

John Bandela
  • 2,416
  • 12
  • 19
  • 1
    Boost 1.54 (to be released in early July) contains four iterator versions of `equal`, `is_permutation` and `mismatch`. You can grab the code off the boost trunk today. – Marshall Clow May 27 '13 at 13:44
1

I got same problem and solved it by checking size of vector before equal.

  std::vector< int > v( 100 );
  std::vector< int > w( 10 );
  bool same = (v.size() == w.size()) && std::equal( v.begin(), v.end(), w.begin() );
Hill
  • 3,391
  • 3
  • 24
  • 28
1

You can also use std::lexicographical_compare twice to determine if either sequence is less than the other.

user541686
  • 205,094
  • 128
  • 528
  • 886