Increment on unique_ptr causes unexpected behaviour of user-defined operator!= - c++

This is a very specific issue and is a bit long to explain, so please bear with me as I try to summarize this as best I can.
I create 2 user types, the first is used inside the second :
struct mySubType {
int val;
mySubType () {}
mySubType ( int _val) : val(_val){}
bool operator!=(const mySubType& rhs) const { return val != rhs.val; }
};
struct myType {
mySubType start;
mySubType stop;
myType () {}
myType (mySubType _start, mySubType _stop) : start(_start), stop(_stop) {}
};
In main(), I create a vector of unique_ptr to myType and fill it as such :
vector<unique_ptr<myType>> v;
for (int i = 0; i < 10; ++i)
v.push_back( unique_ptr<myType>(new myType( mySubType(i), mySubType(i+1))) );
So the val of start and stop for each element is as follows :
start:0 stop:1
start:1 stop:2
start:2 stop:3
start:3 stop:4
start:4 stop:5
start:5 stop:6
start:6 stop:7
start:7 stop:8
start:8 stop:9
start:9 stop:10
start should always be the same as previous stop (this is the case in this example). To check this, I tried the following :
for (auto it = v.begin(); it != --v.end(); )
{
if ((*it)->stop != (*(++it))->start)
cout << "1";
}
To my surprise, the output was : 111111111, all different when they should be all equal.
I tried a few other things to try and understand the source of the error. I replaced the inside of the loop with
mySubType stop = (*it)->stop;
mySubType next_start = (*(++it))->start;
if (stop != next_start)
cout << "2";
and then
if ((*it)->stop.val != (*(++it))->start.val)
cout << "3";
Neither of those printed anything (all tests were correctly solved as equal).
This only happens when using unique_ptr (vector<myType> does not have the same issue). I also tried using post-increment but I get the exact same result.
Does anyone have a clue why this happens ?
I know there are a lot of ways to work around this issue (the 2 above for example). What I'm interested in is why this behaviour happens.

The expression in the if statement
if ((*it)->stop != (*(++it))->start)
has undefined behavior.
It seems you mean the following loop
#include <iterator>
// ...
for (auto it = v.begin(); it != v.end(); ++it )
{
auto next = std::next( it );
if ( next != v.end() && (*it)->stop != (*( next ))->start)
std::cout << "1";
}
Instead of the for loop you could use the standard algorithm std::adjacent_find. For example
#include <iostream>
#include <memory>
#include <vector>
#include <iterator>
#include <algorithm>
struct mySubType {
int val;
mySubType () {}
mySubType ( int _val) : val(_val){}
bool operator!=(const mySubType& rhs) const { return val != rhs.val; }
};
struct myType {
mySubType start;
mySubType stop;
myType () {}
myType (mySubType _start, mySubType _stop) : start(_start), stop(_stop) {}
};
int main()
{
std::vector<std::unique_ptr<myType>> v;
for (int i = 0; i < 10; ++i)
v.push_back( std::unique_ptr<myType>(new myType( mySubType(i), mySubType(i+1))) );
auto it = std::adjacent_find( std::begin( v ), std::end( v ),
[]( const auto &left, const auto &right )
{
return left->stop != right->start;
} );
if ( it != std::end( v ) ) std::cout << "there is an error\n";
else std::cout << "The sequence is correct\n";
}
The program output is
The sequence is correct

Related

how to display common character if the two letters is equal in vector

For example I have vector {'a','a','b','b','c'} and I want to get the most letters which is a and b but this code the output is a;
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int getMostFrequentElement(std::vector<char> &arr)
{
if (arr.empty())
return -1;
std::sort(arr.begin(), arr.end());
auto last_int = arr.front();
auto most_freq_int = arr.front();
int max_freq = 0, current_freq = 0;
for (const auto &i : arr) {
if (i == last_int)
++current_freq;
else {
if (current_freq > max_freq) {
max_freq = current_freq;
most_freq_int = last_int;
}
last_int = i;
current_freq = 1;
}
}
if (current_freq > max_freq) {
max_freq = current_freq;
most_freq_int = last_int;
}
return most_freq_int;
}
int main(){
std::vector<char> arr = {'a','a','b','b','c'};
char ret = getMostFrequentElement(arr);
std::cout << "Most frequent element = " << ret;
}
May I know why my output becomes a instead a and b?
input vector arr{'a','a','b','b','c'}
expected output is a and b
but my output is a
Your function returns only the first most frequent character as an integer in a sorted vector.
For starters the implementation of the function is not good. The function shall not sort the passed by reference vector. It is the owner of the vector decides whether to sort the vector before calling the function. The function shall not modify the passed to it vector.
If you want that the function would return all most frequent characters in a vector then you need to change the function essentially.
For example the function can look the following way as it is shown in the demonstrative program below.
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>
std::vector<char> getMostFrequentElement( const std::vector<char> &v )
{
std::vector<char> result;
std::map<char, size_t> m;
for ( const auto &c : v ) ++m[c];
auto it = std::max_element( std::begin( m ), std::end( m ),
[]( const auto &p1, const auto &p2 )
{
return p1.second < p2.second;
} );
if ( it != std::end( m ) )
{
for ( const auto &p : m )
{
if ( p.second == it->second ) result.push_back( p.first );
}
}
return result;
}
int main()
{
std::vector<char> v = { 'a', 'a', 'b', 'b', 'c' };
auto result = getMostFrequentElement( v );
for ( const auto &c : result ) std::cout << c << ' ';
std::cout << '\n';
return 0;
}
The program output is
a b
The answer from Vlad is good and should be accepted.
I would like to show an additional, more "mordern" C++ solution.
The Function body is rather compact and consists only of 3 lines of code. It will count all occurences of char and sort it in decreasing order regarding the occurence.
So, the caller of this function can show all kind of information. In the example below, I show all topmost elements.
But all kind of other evaluations may be shown.
Please see:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <set>
#include <iterator>
#include <unordered_map>
// Writing some aliases to prevent later typing work and make the code a little bit more readable. ---------------------
using DataType = char;
using CounterType = unsigned int;
using Pair = std::pair<DataType, CounterType>;
using Counter = std::unordered_map<DataType, CounterType>;
using Data = std::vector<DataType>;
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using CountedAndSorted = std::multiset<Pair, Comp>;
// ----------------------------------------------------------------------------------------------------------------------
CountedAndSorted getMostFrequentElement(Data& data) {
// Count
Counter counter{};
for (const char c : data) counter[c]++;
// Return counted and sorted result
return {counter.begin(), counter.end()};
}
// ------------------------
// Test/Driver code
int main() {
// Test Data
Data d = { 'a', 'a', 'b', 'b', 'c' };
// Calculate result
auto result = getMostFrequentElement(d);
// Show output
for (const auto& [c, count] : result) if (count == result.begin()->second) std::cout << c << ' ';
}

remove character from macro parameter

I'm trying to create a macro to replace the for-loop
I want it to work like this:
f(var, start, Eend)
where var is the name of the loop variable, the start is the value where it begins and end, the value where it stops. The E is a symbol that can exist or not. If it exist, it is =
my macro is actually like this:
#define f(var, s, e) for(int var = s, kx = (s<e? 1 : -1); var != e; var += kx)
but this definition cannot afford = yet, so I want to extend it like this:
f(i, 10, =15) cout<<" "<<i;
output: 10 11 12 13 14 15
My question is if it's possible to remove the first char of the Eend argument of macro.
I can discover if it's equal using
#Eend[0] == '='
but after I cant use Eend to compare with s and find out if I must use ++ or --
This is what I want:
#define f(var, s, Eend)
for(int var = s, kx = s<end? 1:-1, LIM = #Eend[0] == '='? end+kx : end; var!=end; var += kx)
where end is Eend without the '=' (if it exists)
For your macro question you can simply define two macros, with slightly different (hopefully mnemonic) names.
E.g., if I understand the intention correctly,
#define xf(var, s, e) for(int var = s, kx = (s<e? 1 : -1); var != e; var += kx)
#define f(var, s, e) for(int var = s, kx = (s<e? 1 : -1), e2 = e + kx; var != e2; var += kx)
If the redundancy of that is not palatable, then you can express them in terms of a third common implementation macro.
Doing this without a macro is more work, but you only have to do the definition work once.
And you avoid possible name collisions for the macro.
E.g. it can go like this:
enum From { from };
enum To { to };
enum To_before { to_before };
class Sequence
{
private:
int first_;
int after_;
int delta_;
public:
class Iter
{
friend class Sequence;
private:
Sequence const* p_seq_;
int current_;
Iter( Sequence const& seq )
: p_seq_( &seq )
, current_( seq.first_ )
{}
Iter( Sequence const& seq, int const current )
: p_seq_( &seq )
, current_( current )
{}
public:
friend auto operator==( Iter const& a, Iter const& b )
-> bool
{ return a.current_ == b.current_; } // UB if not same sequence.
friend auto operator!=( Iter const& a, Iter const& b )
-> bool
{ return a.current_ != b.current_; }
auto operator*() const
-> int
{ return current_; }
auto operator++()
-> Iter&
{
current_ += p_seq_->delta_;
return *this;
}
auto operator++( int )
-> Iter
{
Iter result{ *this };
current_ += p_seq_->delta_;
return result;
}
};
auto begin() const -> Iter { return Iter{ *this }; }
auto end() const -> Iter { return Iter{ *this, after_ }; }
Sequence( int const first, int const last, bool inclusive = true )
: first_( first )
, after_( last )
, delta_( first <= last? 1 : -1 )
{ if( inclusive ) { after_ += delta_; } }
Sequence( From, int const first, To, int const last )
: Sequence( first, last, true )
{}
Sequence( From, int const first, To_before, int const last )
: Sequence( first, last, false )
{}
};
#include <iostream>
using namespace std;
auto main()
-> int
{
using Seq = Sequence;
for( int const i : Seq{ from, 10, to, 15 } ) { cout << i << ' '; }
cout << endl;
for( int const i : Seq{ from, 15, to, 10 } ) { cout << i << ' '; }
cout << endl;
cout << endl;
for( int const i : Seq{ from, 10, to_before, 15 } ) { cout << i << ' '; }
cout << endl;
for( int const i : Seq{ from, 15, to_before, 10 } ) { cout << i << ' '; }
cout << endl;
}

C++: read dataset and check if vector<Class> is subset of vector<Class>

I have the following piece of code. The code creates a vector Dataset, each element of which is a vector. It also creates a vector S.
I want to check which vector of Dataset contain vector of S. Apparently I am doing something wrong, because for the following example,
Dataset is:
a b c
a d
a b d
and S:
a b
it should print: 0 2
and for me it prints: 0 1 2
#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#include <algorithm>
using namespace std;
class StringRef
{
private:
char const* begin_;
int size_;
public:
int size() const { return size_; }
char const* begin() const { return begin_; }
char const* end() const { return begin_ + size_; }
StringRef( char const* const begin, int const size )
: begin_( begin )
, size_( size )
{}
bool operator<(const StringRef& obj) const
{
return (strcmp(begin(),obj.begin()) > 0 );
}
};
/************************************************
* Checks if vector B is subset of vector A *
************************************************/
bool isSubset(std::vector<StringRef> A, std::vector<StringRef> B)
{
std::sort(A.begin(), A.end());
std::sort(B.begin(), B.end());
return std::includes(A.begin(), A.end(), B.begin(), B.end());
}
vector<StringRef> split3( string const& str, char delimiter = ' ' )
{
vector<StringRef> result;
enum State { inSpace, inToken };
State state = inSpace;
char const* pTokenBegin = 0; // Init to satisfy compiler.
for(auto it = str.begin(); it != str.end(); ++it )
{
State const newState = (*it == delimiter? inSpace : inToken);
if( newState != state )
{
switch( newState )
{
case inSpace:
result.push_back( StringRef( pTokenBegin, &*it - pTokenBegin ) );
break;
case inToken:
pTokenBegin = &*it;
}
}
state = newState;
}
if( state == inToken )
{
result.push_back( StringRef( pTokenBegin, &str.back() - pTokenBegin ) );
}
return result;
}
int main() {
vector<vector<StringRef> > Dataset;
vector<vector<StringRef> > S;
ifstream input("test.dat");
long count = 0;
int sec, lps;
time_t start = time(NULL);
cin.sync_with_stdio(false); //disable synchronous IO
for( string line; getline( input, line ); )
{
Dataset.push_back(split3( line ));
count++;
};
input.close();
input.clear();
input.open("subs.dat");
for( string line; getline( input, line ); )
{
S.push_back(split3( line ));
};
for ( std::vector<std::vector<StringRef> >::size_type i = 0; i < S.size(); i++ )
{
for(std::vector<std::vector<StringRef> >::size_type j=0; j<Dataset.size();j++)
{
if (isSubset(Dataset[j], S[i]))
{
cout << j << " ";
}
}
}
sec = (int) time(NULL) - start;
cerr << "C++ : Saw " << count << " lines in " << sec << " seconds." ;
if (sec > 0) {
lps = count / sec;
cerr << " Crunch speed: " << lps << endl;
} else
cerr << endl;
return 0;
}
Your StringRef type is dangerous because it contains a const char * pointer, but no concept of ownership. So the pointer could be invalidated at some point after the object is constructed.
And indeed this is what happens here: You have a single string (line) and create StringRefs with pointers to its internal data. When the string is later modified, these pointers are invalidated.
You should create a vector<std::string> instead to prevent this problem.

I cannot make a copy constructor for a bidirectional map

I am in my first year of c++ at university and in some days i have exam.
I work hard for this exam not only to succeed but to succeed with the best mark.
In this code that I post I have to make a bidirectional map which i was able to do and some other functions for it.
The problem comes when i try to make a copy constructor for this bidirectional map.
I know it is a little shameful to come to you guys with this minor problem but I last give a try.
If someone of you has patience to help me i will be very happy to succeed with high mark at my c++ exam.
So here is the header where i create a bidirectional map.This contains 2 maps: one stores the key and the value and other stores the value like key and the first key like the value. The problem comes when i have to do a copy constructor and I not have the optimal knowledge to do this.
#ifndef BIMAP_H_INCLUDED
#define BIMAP_H_INCLUDED
#include<map>
#include <utility>
template <class T>
class BidirectionalMap
{
public:
BidirectionalMap(){};
BidirectionalMap(typename std::multimap<T,T>::iterator beg, typename std::multimap<T,T>::iterator end)
{
m1.insert(beg,end
}
void insert(T a, T b)
{
m1.insert(std::pair<T,T> (a,b));
m2.insert(std::pair<T,T> (b,a));
}
BidirectionalMap& operator =(const BidirectionalMap &c)
{
m1=c.m1;
m2=c.m2;
return *this;
}
const T& at(const T &a) const
{
if(m2.find(a)!=m2.end()) return m2.at(a);
else return m1.at(a);
}
int count(const T &a) const
{
if(m2.find(a)!=m2.end()) return m2.count(a);
else if(m1.find(a)!=m1.end()) return m1.count(a);
else return 0;
}
void erase(const T &a)
{
if(m1.find(a)!=m1.end())
{
T b=m1[a];
m1.erase(a);
m2.erase(b);
}
else
{
T b=m2[a];
m2.erase(a);
m1.erase(b);
}
}
int size() const
{
return m1.size();
}
typename std::map<T,T>::const_iterator begin() const
{
return m1.begin();
}
typename std::map<T,T>::const_iterator end() const
{
return m1.end();
}
private:
std::map<T,T> m1;
std::map<T,T> m2;
};
#endif // BIMAP_H_INCLUDED
And here is the main() where i use that bidirectional map.Do not focus on 2,3,4 but only on 5 because just there I have no idea.
#include <map>
#include <functional>
#include <iostream>
#include <algorithm>
#include <string>
#include "bimap.h"
struct LengthSum
{
int length;
LengthSum():length(0) {}
void operator()(const std::pair<std::string, std::string>& p)
{
length += p.first.length();
length += p.second.length();
}
};
const int max = 1000;
int main()
{
int yourMark = 1;
// 2-es
BidirectionalMap<int> fun;
for( int i = 1; i <= max; ++i )
fun.insert( i, i + max );
BidirectionalMap<std::string> tel;
tel.insert( "Aniko", "+36(70)555-8124" );
tel.insert( "Botond", "+36(30)555-4321" );
const BidirectionalMap<std::string> ctel = tel;
if ( fun.at( 1 ) == (1 + max) &&
ctel.at( "+36(30)555-4321" ) == "Botond" )
{
yourMark = ctel.count( "Aniko" ) +
fun.count( max * 2 ) +
ctel.count( "Unknown" );
}
// 3-as
tel.erase( "+36(70)555-8124" );
if ( 0 == tel.count( "Aniko" ) &&
max == fun.size() )
{
yourMark = ctel.size() + tel.size();
}
// 4-es
const int l = std::for_each( ctel.begin(), ctel.end(), LengthSum() ).length;
yourMark = l/10;
// 5-os
std::map<double, double> md;
md[1.12] = 8.8;
md[5.4] = 7.5;
std::multimap<int, int> mmi;
mmi.insert( std::make_pair( 1, 2 ) );
mmi.insert( std::make_pair( 3, 6 ) );
mmi.insert( std::make_pair( 5, 8 ) );
//Here is the problem because i don`t know to do this :
const BidirectionalMap<int> b( mmi.begin(), mmi.end() );//??
const BidirectionalMap<double> bd( md.begin(), md.end() );//??
if ( b.at(8) == 5 )
{
yourMark = b.size() +
bd.size() +
b.count( 9 );
}
std::cout << "Your mark is " << yourMark;
std::endl( std::cout );
}
For the 2,3,4 marks i succeeded but when it comes for the best mark(5 in my country) i crashed.
So if you have the time and patience PLEASE help me :(
First of all, you are trying to copy a multimap into a map. Multimaps can have multiple items with the same index stored, while a map has only one item per index.
So, you may have to iterate over the incoming range and insert the map element wise into your maps. What you do if you have multiple indices stored in the multimap you have to decide for yourself.
Edit:
To be compatible with both map and multimap you can always make the iterator a template argument:
template<typename TIter>
BidirectionalMap(TIter beg, TIter end) {
for(TIter it = beg; it != end; ++it) {
// insert elements
}
}
I solved it like this with help from #MatthiasB
BidirectionalMap(Titer beg, Titer end)
{
for(Titer it = beg; it != end; ++it)
{
m1.insert(*it);
m2.insert(std::pair<T,T> (it->second,it->first));
}

Iterating C++ vector from the end to the beginning

Is it possible to iterate a vector from the end to the beginning?
for (vector<my_class>::iterator i = my_vector.end();
i != my_vector.begin(); /* ?! */ ) {
}
Or is that only possible with something like that:
for (int i = my_vector.size() - 1; i >= 0; --i) {
}
One way is:
for (vector<my_class>::reverse_iterator i = my_vector.rbegin();
i != my_vector.rend(); ++i ) {
}
rbegin()/rend() were especially designed for that purpose. (And yes, incrementing a reverse_interator moves it backward.)
Now, in theory, your method (using begin()/end() & --i) would work, std::vector's iterator being bidirectional, but remember, end() isn't the last element — it's one beyond the last element, so you'd have to decrement first, and you are done when you reach begin() — but you still have to do your processing.
vector<my_class>::iterator i = my_vector.end();
while (i != my_vector.begin())
{
--i;
/*do stuff */
}
UPDATE: I was apparently too aggressive in re-writing the for() loop into a while() loop. (The important part is that the --i is at the beginning.)
If you have C++11 you can make use of auto.
for (auto it = my_vector.rbegin(); it != my_vector.rend(); ++it)
{
}
Starting with c++20, you can use a std::ranges::reverse_view and a range-based for-loop:
#include<ranges>
#include<vector>
#include<iostream>
using namespace std::ranges;
std::vector<int> const vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(auto& i : views::reverse(vec)) {
std::cout << i << ",";
}
Or even
for(auto& i : vec | views::reverse)
Unfortunately, at the time of writing (Jan 2020) no major compiler implements the ranges library, but you can resort to Eric Niebler's ranges-v3:
#include <iostream>
#include <vector>
#include "range/v3/all.hpp"
int main() {
using namespace ranges;
std::vector<int> const vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(auto& i : views::reverse(vec)) {
std::cout << i << ",";
}
return 0;
}
The well-established "pattern" for reverse-iterating through closed-open ranges looks as follows
// Iterate over [begin, end) range in reverse
for (iterator = end; iterator-- != begin; ) {
// Process `*iterator`
}
or, if you prefer,
// Iterate over [begin, end) range in reverse
for (iterator = end; iterator != begin; ) {
--iterator;
// Process `*iterator`
}
This pattern is useful, for example, for reverse-indexing an array using an unsigned index
int array[N];
...
// Iterate over [0, N) range in reverse
for (unsigned i = N; i-- != 0; ) {
array[i]; // <- process it
}
(People unfamiliar with this pattern often insist on using signed integer types for array indexing specifically because they incorrectly believe that unsigned types are somehow "unusable" for reverse indexing)
It can be used for iterating over an array using a "sliding pointer" technique
// Iterate over [array, array + N) range in reverse
for (int *p = array + N; p-- != array; ) {
*p; // <- process it
}
or it can be used for reverse-iteration over a vector using an ordinary (not reverse) iterator
for (vector<my_class>::iterator i = my_vector.end(); i-- != my_vector.begin(); ) {
*i; // <- process it
}
User rend() / rbegin() iterators:
for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)
template<class It>
std::reverse_iterator<It> reversed( It it ) {
return std::reverse_iterator<It>(std::forward<It>(it));
}
Then:
for( auto rit = reversed(data.end()); rit != reversed(data.begin()); ++rit ) {
std::cout << *rit;
Alternatively in C++14 just do:
for( auto rit = std::rbegin(data); rit != std::rend(data); ++rit ) {
std::cout << *rit;
In C++03/11 most standard containers have a .rbegin() and .rend() method as well.
Finally, you can write the range adapter backwards as follows:
namespace adl_aux {
using std::begin; using std::end;
template<class C>
decltype( begin( std::declval<C>() ) ) adl_begin( C&& c ) {
return begin(std::forward<C>(c));
}
template<class C>
decltype( end( std::declval<C>() ) ) adl_end( C&& c ) {
return end(std::forward<C>(c));
}
}
template<class It>
struct simple_range {
It b_, e_;
simple_range():b_(),e_(){}
It begin() const { return b_; }
It end() const { return e_; }
simple_range( It b, It e ):b_(b), e_(e) {}
template<class OtherRange>
simple_range( OtherRange&& o ):
simple_range(adl_aux::adl_begin(o), adl_aux::adl_end(o))
{}
// explicit defaults:
simple_range( simple_range const& o ) = default;
simple_range( simple_range && o ) = default;
simple_range& operator=( simple_range const& o ) = default;
simple_range& operator=( simple_range && o ) = default;
};
template<class C>
simple_range< decltype( reversed( adl_aux::adl_begin( std::declval<C&>() ) ) ) >
backwards( C&& c ) {
return { reversed( adl_aux::adl_end(c) ), reversed( adl_aux::adl_begin(c) ) };
}
and now you can do this:
for (auto&& x : backwards(ctnr))
std::cout << x;
which I think is quite pretty.
Use reverse iterators and loop from rbegin() to rend()
I like the backwards iterator at the end of Yakk - Adam Nevraumont's answer, but it seemed complicated for what I needed, so I wrote this:
template <class T>
class backwards {
T& _obj;
public:
backwards(T &obj) : _obj(obj) {}
auto begin() {return _obj.rbegin();}
auto end() {return _obj.rend();}
};
I'm able to take a normal iterator like this:
for (auto &elem : vec) {
// ... my useful code
}
and change it to this to iterate in reverse:
for (auto &elem : backwards(vec)) {
// ... my useful code
}
If you can use The Boost Library, there is the Boost.Range that provides the reverse range adapter by including:
#include <boost/range/adaptor/reversed.hpp>
Then, in combination with a C++11's range-for loop, you can just write the following:
for (auto& elem: boost::adaptors::reverse(my_vector)) {
// ...
}
Since this code is briefer than the one using the iterator pair, it may be more readable and less prone to errors as there are fewer details to pay attention to.
Here's a super simple implementation that allows use of the for each construct and relies only on C++14 std library:
namespace Details {
// simple storage of a begin and end iterator
template<class T>
struct iterator_range
{
T beginning, ending;
iterator_range(T beginning, T ending) : beginning(beginning), ending(ending) {}
T begin() const { return beginning; }
T end() const { return ending; }
};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usage:
// for (auto e : backwards(collection))
template<class T>
auto backwards(T & collection)
{
using namespace std;
return Details::iterator_range(rbegin(collection), rend(collection));
}
This works with things that supply an rbegin() and rend(), as well as with static arrays.
std::vector<int> collection{ 5, 9, 15, 22 };
for (auto e : backwards(collection))
;
long values[] = { 3, 6, 9, 12 };
for (auto e : backwards(values))
;
can try this one (only for --i):
std:vector<int> vec = {1, 2, 3};
size_t i{ vec.size() - 1 };
while (i < size_t(-1))
{
auto& el = vec[i];
--i;
}
use this code
//print the vector element in reverse order by normal iterator.
cout <<"print the vector element in reverse order by normal iterator." <<endl;
vector<string>::iterator iter=vec.end();
--iter;
while (iter != vec.begin())
{
cout << *iter << " ";
--iter;
}
As I don't want to introduce alien-like new C++ syntax, and I simply want to build up on existing primitives, the below snippets seems to work:
#include <vector>
#include <iostream>
int main (int argc,char *argv[])
{
std::vector<int> arr{1,2,3,4,5};
std::vector<int>::iterator it;
// iterate forward
for (it = arr.begin(); it != arr.end(); it++) {
std::cout << *it << " ";
}
std::cout << "\n************\n";
if (arr.size() > 0) {
// iterate backward, simple Joe version
it = arr.end() - 1;
while (it != arr.begin()) {
std::cout << *it << " ";
it--;
}
std::cout << *it << " ";
}
// iterate backwards, the C++ way
std::vector<int>::reverse_iterator rit;
for (rit = arr.rbegin(); rit != arr.rend(); rit++) {
std::cout << *rit << " ";
}
return 0;
}