Is there a safe alternative to std::equal? - c++

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?

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.

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

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

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() );

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

Related

How to reliably "clamp" an iterator?

I'm iterating through a vector as follows:
for(auto it = myVector.begin(); it != myVector.end(); ++it){
// Do some stuff
}
Inside the loop, based on some condition, I add a variable amount to the iterator so as to "jump forward" (but, importantly, never "move back"). What is the "right" way (or, at least, what is an effective/reliable way) to "clamp" the iterator such that I don't end up going beyond the end of the vector (ending up with a program crash or, worse yet, undefined behaviour)?
if (myVector.end() - it < variable_amount)
it += variable_amount;
else
break;
Using std::distance and std::advance would allow this to work with non-random access iterators, but that would be an inefficient algorithm for them, so I recommend not using them.
Algorithm for non-random-access iterators:
for (; variable_amount-- && it != myList.end(); ++it);
You can make your own version of advance that will never go past the end iterator. Adapted from https://en.cppreference.com/w/cpp/iterator/advance
// Assumes c++11 at least
template<class It, class Distance>
constexpr void clamped_advance(It& it, It limit, Distance n) {
using category = typename std::iterator_traits<It>::iterator_category;
static_assert(std::is_base_of<std::input_iterator_tag, category>::value, "Cannot advance non-input iterator");
auto dist = typename std::iterator_traits<It>::difference_type(n);
assert(("Can only clamped_advance forward", dist >= 0));
if (std::is_base_of<std::random_access_iterator_tag, category>::value)
std::advance(it, std::min(dist, std::distance(it, limit)));
else
while (dist-- > 0 && it != limit) ++it;
}
And you can use it like:
for (auto it = myVector.begin(); it != myVector.end(); ++it) {
// Do some stuff
// If this was going to advance past the end, `it` would equal `myVector.end()`
// and the loop will stop
clamped_advance(it, myVector.end(), variableAmount);
}
I would begin by getting the distance between the current iterator and the begin iterator.
If that distance plus the offset is larger than the vector size, you're going out of bounds.

Is There an Alternative to insert and then sort

If I have vector<int> foo and vector<int> bar both of which are sorted, and I want to merge them into foo such that the final result is sorted, does the standard provide me a method for doing this?
Obviously I can do:
foo.insert(foo.end(), bar.begin(), bar.end());
sort(foo.begin(), foo.end());
But I was hoping there was a one step algorithm to accomplish this.
It might be faster to use std::inplace_merge instead of std::sort. If there is additional memory available it has linear complexity otherwise it falls back to NlogN.
auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
std::inplace_merge(foo.begin(), middle, foo.end());
To elaborate on Mat's comment your code could look like this using std::merge:
std::vector<int> result;
std::merge(
foo.begin(), foo.end(),
bar.begin(), bar.end(),
std::back_inserter(result));
foo = result; // if desired
If you need this kind of merge, why not make one yourself?
template <class Vector>
void insert_sorted(Vector& where, Vector& what)
{
typename Container::iterator src = what.begin();
typename Container::iterator src_end = what.end();
size_t index = 0;
while(src != src_end)
{
if(*src < where[index])
{
where.insert(where.begin() + index, *src);
++src;
}
++index;
}
}
Sample usage:
vector<int> foo{ 0, 5, 7, 9, 11, 14 };
vector<int> bar{ 1, 2, 4, 8, 10, 12 };
insert_sorted(foo, bar);
for(vector<int>::iterator i = foo.begin(); i != foo.end(); ++i)
cout << *i << " ";
Output:
0 1 2 4 5 7 8 9 10 11 12 14
Live sample: link.
So after looking through all the standard algorithms I can confirm that, there is no alternative to insert and sort. As I was searching the standard algorithms I did note that all the copying algorithms use input iterators and output iterators the only time an input-output iterators are used is when a single range is being operated on. (For example sort uses input-output iterators but any copy uses input iterators and an output iterator.)
I'd like to give an illustration of my point. So lets make an example of what an insertion merge algorithm with an input-output iterator would look like:
template <class BidirectionalIterator, class InputIterator>
void func(BidirectionalIterator first1, BidirectionalIterator last1, InputIterator first2, InputIterator last2){
bool is1Empty = first1 == last1;
bool is2Empty = first2 == last2;
BidirectionalIterator end = next(last1, distance(first2, last2));
if (!is1Empty){
--last1;
}
if (!is2Empty){
--last2;
}
while (!is1Empty || !is2Empty){
--end;
if (!is1Empty){
if (!is2Empty && *last2 > *last1){
*end = *last2;
if (last2 == first2){
is2Empty = true;
}else{
--last2;
}
}else{
*end = *last1;
if (last1 == first1){
is1Empty = true;
}
else{
--last1;
}
}
}else{
*end = *last2;
if (last2 == first2){
is2Empty = true;
}
else{
--last2;
}
}
}
}
Two things should be noted about this func algorithm:
It doesn't respect last1 it is assumed that sufficient space is allocated beyond last1 to also contain all the elements in the input range
func's input-output range cannot be called with a back_inserter like any other output only range in a standard algorithm
Because of this even func cannot be a "one step algorithm". It must be called like this:
foo.resize(foo.size() + bar.size());
func(foo.begin(), next(foo.begin(), foo.size() - bar.size()), bar.begin(), bar.end());
Note that Blastfurnace's answer takes advantage of the knowledge that it is merging two sorted ranges, and as such is of equivalent speed to func:
auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
inplace_merge(foo.begin(), middle, foo.end());
The only actual "one step algorithm" is to roll this Blastfurnace's answer into a function that you could call by passing in the containers to be merged.

Best way to further split some elements in vector

Here is a sample vector
vector<string> v;
v.push_back("one");
v.push_back("two");
v.push_back("three four");
v.push_back("five");
// print
one
two
three four
five
i need to split the element number 3 so now the vector look (without creating another vector)
// print
one
two
three
four
five
Should i use iterator or simple loop? it should have good performance too.
As has been pointed out in the comments, if you're inserting
elements into the vector (which you will be), you have to avoid
using an invalidated iterator. Still, something along the lines
of the following should work:
std::vector<std::string> iter = v.begin();
while ( iter != v.end() ) {
std::string::iterator breakpoint = std::find( iter->begin(), iter->end(), ' ' );
if ( breakpoint == iter->end() ) {
++ iter;
} else {
std::string next( breakpoint + 1, iter->end() );
iter->erase( breakpoint, iter->end() );
iter = v.insert( iter + 1, next );
}
}
In such cases, I generally prefer generating into a copy,
however.

How to handle checked iterators?

for debug mode in VS2013 I receive an out of range exception if I add a constant value to an iterator and this iterator will go out of range afterwards.
For example:
#include <cstdlib>
#include <vector>
int main(void) {
std::vector<unsigned char> data(10, 0);
auto it = data.begin();
while (it != data.end()) {
if ((it + 3) <= data.end()) {
it += 3;
}
else {
it = data.end();
}
}
return EXIT_SUCCESS;
}
In the fourth run of the while-loop the check it + 3 <= data.end() fails and the exception is thrown.
A short workaround for the VS compiler would be to insert #define _ITERATOR_DEBUG_LEVEL 0 that disables the option for checked iterators in debug mode.
But I would appreciate a better, common solution that will work for both, VS and GCC compiler!
I'm sure there already exists a way by the STL to handle iterator distances and checks like this :) but I don't know it yet...
The better common solution is the following
while ( std::distance( it, data.end() ) >= 3 )
{
// some code
std::advance( it, 3 );
// some code
}
Or
while ( it != data.end() )
{
// some code
std::advance( it, std::min<int>( 3, std::distance( it, data.end() ) ) );
// some code
}
The choice between these two variants depends on whether you want to process the iterator at least one time even if data.end() - it is less than 3.
If a non-random access iterator is used then the loop can look as
while ( it != data.end() )
{
// some code
( ++it != data.end() ) && ( ++it != data.end() ) && ( ++it != data.end() );
// some code
}
That's because end() points to the element beyond the last actual element of the vector. So your condition if ((it + 3) <= data.end()) will eventually evaluate to end() + 1 (when it already equals end()), which is invalid. To fix it, change it to if ((it + 3) < data.end()).
To reiterate: the last available element of a vector, or any other STL container, is located at end() - 1. If the container is empty, begin() is the same as end(). It is always an error to dereference an iterator pointing to end().

Increment an iterator c++

My problem is as follows: I use an iterator, and I want to compare each element to the next element. Prototype looks like below, how can I increase the iterator to be able to compare?
Also, how can I set a proper condition for this to happen? I mean how to point on the last element, not on the next after the last like with end() function:
std::vector<T>::const_iterator it;
std::vector<T>::const_iterator it2;
for (it = set.begin(), it != set.end(); it++)
{
// some things happen
if ( final == it )
{
if ( it != set.end()-1 ) // how to write properly condition?
{
it2 = it + 1; //how to assign the next here?
if (...)//some condition
{
if ( it->func1() - it2->func1()) < 20 ) //actual comparison of two consecutive element values
// do something
}
}
}
}
In C++11 use the functions std::next() and std::prev().
Your code could become:
// before
it != std::set.end()-1
// after
it != std::prev(set.end())
and
// before
it2 = it + 1;
// after
it2 = std::next(it);
That is true also for non-vector containers, such as map,set or others.
NOTE: after std::next(it), "it" iterator remains unmodified!
NOTE 2: Use it2 = std::next(it,n); to increment as much as you need.
You can use adjacent_find to solve that. You should use the second form of that function (with predicate) and pass to the predicate your some things happen and some condition in c-tor
auto found = std::adjacent_find( set.begin(), set.end(),
[some_comdition]( const T & left, const T & right ) {
if ( some_comdition ) {
if ( left.func1() - right.func1() < 20 ) {
do_smth();
// return true; if there's no need to continue
}
}
return false;
}
);
Based on the fact that it++ is acceptable, we should define a new iterator called itplusone, which is initialized as itplusone = ++it. In this way, you can safely use the meaning of an iterator pointing to the next item of it. Also clearly, the range of iterator of itplusone bounded by terms itplusone != set.end(). I use this method to compute the total weight of a path, which is defined as a list object.
In the for loop, you use it++ which means it = it + 1, which is perfectly ok. So this one will be fine also it2 = it + 1. it2 will be pointing to the next value.
In the for loop again, you use it != set.end(), which is again perfectly ok. So you can also it + 1 < set.end(), just like you did in your code.
I don't see anything wrong in your code, just wanted to explain.
somewhat late, just discovered it, but like mentioned above, ++ iterator works fine.
vector<string> P
auto itA = begin(P);
while(itA != end(P))
{
if(itA != end(P))
{
++itA; //
}
}