std::equal

When you compare two sequences, you are usually interested to know if any couple are equals or if there is at least one difference. If this is the case, you can use the std::equal(). But you should put some care in using it, you can't compare apples with oranges and you should ensure the first sequence is not shorter than the second, since the comparison is done for each element of the first one, till a difference, or the end, is met. If the second sequence is shorter, we risk a catastrophic dereferencing of an invalid iterator.

Here is the class I used as a base for creating a couple of tests for std::equal():

class EqualTest : public ::testing::Test
{
protected:
EqualTest()
{
vi_.reserve(10);
vc_.reserve(10);

for(int i = 0; i < 10; ++i)
vi_.push_back(i * i);

std::copy(vi_.begin(), vi_.end(), std::back_inserter(vc_));
}

std::vector<int> vi_;
std::vector<int> vc_;
};

In the first test I show the normal usage, we simply pass to equal() the beginning/end iterators for the first sequence, and just the beginning of the second one. Notice that before using equal() I also made a test on the vector sizes, to ensure we don't risk a crash while comparing:

TEST_F(EqualTest, Same)
{
ASSERT_GE(vi_.size(), vc_.size());
EXPECT_TRUE(std::equal(vi_.begin(), vi_.end(), vc_.begin()));
}

The second test is more interesting, since we use a custom comparison function (actually, a lambda function) to force std::equal() to behave how we want:

TEST_F(EqualTest, Lambda)
{
const int step = 3;
std::for_each(vi_.begin(), vi_.end(), [step](int& i){ i += step; });

ASSERT_GE(vi_.size(), vc_.size());
EXPECT_TRUE(std::equal(vi_.begin(), vi_.end(), vc_.begin(),
[step](int i, int j) { return i == j + step; } ));
}

No comments:

Post a Comment