reverse_iterator and const_reverse_iterator

J

Jess

Hello,

I think the two reverse_iterators are the same, except that the const_
version doesn't allow me to change the value pointed to by the
iterators. However, I have a program that works for reverse_iterator
but not const_reverse_iterator:

for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;

This one fails, with error

no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'

If I replace const_reverse_iterator with reverse_iterator, then
everything works fine. Is there some subtle difference between the
two iterators?

Thanks,
Jess
 
R

Roland Pibinger

I think the two reverse_iterators are the same, except that the const_
version doesn't allow me to change the value pointed to by the
iterators. However, I have a program that works for reverse_iterator
but not const_reverse_iterator:

for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;

This one fails, with error

no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'

I guess your compiler cannot distinguish between the const and the
non-const rend(). Try:

for(vector<int>::const_reverse_iterator i = v.rbegin();
i != ((const std::vector<int>) v).rend();
++i)
 
V

V. R. Marinov

>If I replace const_reverse_iterator with reverse_iterator, then
>everything works fine. Is there some subtle difference between the
>two iterators?

Yes. Basicly these are two different types/classes.

>However, I have a program that works for reverse_iterator
>but not const_reverse_iterator:
>for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
>++i)
> cout << (*i) << endl;


There are two overloaded rend(void) functions, that differ in their
return types. Now C++ does NOT permit function overloading by return
value. So the function "const_reverse_iterator rend() const" could be
applied on const objects only, but not on non constant ones.


int arr[] = {1, 2, 3};
const vector<int> v(arr, arr+3);

typedef vector<int>::const_reverse_iterator ViCRI;
for(ViCRI i = v.rbegin(); i!=v.rend(); ++i)
cout << (*i) << endl;


And the function "reverse_iterator rend()" can be applied on non
constant objects only.

One way get around it is to explicitly cast the result returned by
rend(). And here is a different way deal with this:


int arr[] = {1, 2, 3};
const vector<int> v(arr, arr+3);

typedef vector<int>::const_reverse_iterator ViCRI;
for(ViCRI i = v.rbegin(), End = v.end(); i!=End; ++i)
cout << (*i) << endl;
 
P

Pete Becker

Roland said:
I think the two reverse_iterators are the same, except that the const_
version doesn't allow me to change the value pointed to by the
iterators. However, I have a program that works for reverse_iterator
but not const_reverse_iterator:

for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;

This one fails, with error

no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'

I guess your compiler cannot distinguish between the const and the
non-const rend(). Try:

Seems like it does distinguish between them, and calls the non-const
version on a non-const vector. The problem arises from comparing a
const_iterator to a plain iterator.
for(vector<int>::const_reverse_iterator i = v.rbegin();
i != ((const std::vector<int>) v).rend();

i != ((const std::vector<int>&) v).rend();

That's a minor typo, but critical. As written, it copies the vector,
creating an iterator that points into the copy rather than the original.

A simpler way of doing this, if you have a library that conforms to the
not-yet-official C++0x standard, is to call crbegin() and crend()
instead of rbegin() and rend(). crbegin() and crend() return const
iterators.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
J

Jess

Roland said:
I think the two reverse_iterators are the same, except that the const_
version doesn't allow me to change the value pointed to by the
iterators. However, I have a program that works for reverse_iterator
but not const_reverse_iterator:
for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;
This one fails, with error
no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'
I guess your compiler cannot distinguish between the const and the
non-const rend(). Try:

Seems like it does distinguish between them, and calls the non-const
version on a non-const vector. The problem arises from comparing a
const_iterator to a plain iterator.
for(vector<int>::const_reverse_iterator i = v.rbegin();
i != ((const std::vector<int>) v).rend();

i != ((const std::vector<int>&) v).rend();

That's a minor typo, but critical. As written, it copies the vector,
creating an iterator that points into the copy rather than the original.

Thanks, I tried both methods, but neither worked... I think I only
need to cast a non-const "v" to a const "v", hence I tried

for(vector<int>::const_reverse_iterator i = v.rbegin(); i !=
(static_cast<const vector<int> >)v.rend(); ++i)
cout << (*i) << endl;

Unfortunately, it failed as well...Moreover, what's the difference
between casting to a class type and casting to a reference?

Jess
 
J

Jess

If I replace const_reverse_iterator with reverse_iterator, then
everything works fine. Is there some subtle difference between the
two iterators?

Yes. Basicly these are two different types/classes.
However, I have a program that works for reverse_iterator
but not const_reverse_iterator:
for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;

There are two overloaded rend(void) functions, that differ in their
return types. Now C++ does NOT permit function overloading by return
value. So the function "const_reverse_iterator rend() const" could be
applied on const objects only, but not on non constant ones.

int arr[] = {1, 2, 3};
const vector<int> v(arr, arr+3);

typedef vector<int>::const_reverse_iterator ViCRI;
for(ViCRI i = v.rbegin(); i!=v.rend(); ++i)
cout << (*i) << endl;

And the function "reverse_iterator rend()" can be applied on non
constant objects only.

One way get around it is to explicitly cast the result returned by
rend(). And here is a different way deal with this:

int arr[] = {1, 2, 3};
const vector<int> v(arr, arr+3);

typedef vector<int>::const_reverse_iterator ViCRI;
for(ViCRI i = v.rbegin(), End = v.end(); i!=End; ++i)
cout << (*i) << endl;


Thanks. By "explicitly cast the result returned by rend()", do you
mean I should cast const away? Is it done by using "v.end()" instead
of "rend()"? However, why do we need to cast away constness if "v" is
a const vector?

Jess
 
V

V. R. Marinov

Jess напиÑа:
If I replace const_reverse_iterator with reverse_iterator, then
everything works fine. Is there some subtle difference between the
two iterators?

Yes. Basicly these are two different types/classes.
However, I have a program that works for reverse_iterator
but not const_reverse_iterator:
for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;

There are two overloaded rend(void) functions, that differ in their
return types. Now C++ does NOT permit function overloading by return
value. So the function "const_reverse_iterator rend() const" could be
applied on const objects only, but not on non constant ones.

int arr[] = {1, 2, 3};
const vector<int> v(arr, arr+3);

typedef vector<int>::const_reverse_iterator ViCRI;
for(ViCRI i = v.rbegin(); i!=v.rend(); ++i)
cout << (*i) << endl;

And the function "reverse_iterator rend()" can be applied on non
constant objects only.

One way get around it is to explicitly cast the result returned by
rend(). And here is a different way deal with this:

int arr[] = {1, 2, 3};
const vector<int> v(arr, arr+3);

typedef vector<int>::const_reverse_iterator ViCRI;
for(ViCRI i = v.rbegin(), End = v.end(); i!=End; ++i)
cout << (*i) << endl;


Thanks. By "explicitly cast the result returned by rend()", do you
mean I should cast const away? Is it done by using "v.end()" instead
of "rend()"? However, why do we need to cast away constness if "v" is
a const vector?

No. I was referring to the non-const case.

/********************** CODE **********************/


int arr[] = {1, 2, 3};
vector<int> v(arr, arr+3);

typedef vector<int>::const_reverse_iterator ViCRI;

for(ViCRI i = v.rbegin(); i!=ViCRI(v.rend()); ++i)
cout << (*i) << endl;


/********************** CODE **********************/
 
V

V.R. Marinov

Jess :
Roland said:
On Sun, 17 Jun 2007 06:45:56 -0700, Jess wrote:
I think the two reverse_iterators are the same, except that the const_
version doesn't allow me to change the value pointed to by the
iterators. However, I have a program that works for reverse_iterator
but not const_reverse_iterator:
for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;
This one fails, with error
no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'
I guess your compiler cannot distinguish between the const and the
non-const rend(). Try:

Seems like it does distinguish between them, and calls the non-const
version on a non-const vector. The problem arises from comparing a
const_iterator to a plain iterator.
for(vector<int>::const_reverse_iterator i = v.rbegin();
i != ((const std::vector<int>) v).rend();

i != ((const std::vector<int>&) v).rend();

That's a minor typo, but critical. As written, it copies the vector,
creating an iterator that points into the copy rather than the original.

Thanks, I tried both methods, but neither worked... I think I only
need to cast a non-const "v" to a const "v", hence I tried

for(vector<int>::const_reverse_iterator i = v.rbegin(); i !=
(static_cast<const vector<int> >)v.rend(); ++i)
cout << (*i) << endl;

Unfortunately, it failed as well

It looks like you are using the wrong syntax. It should be.

...Moreover, what's the difference
between casting to a class type and casting to a reference?

Please reread Pete Becker's post.
 
R

Roland Pibinger

Thanks, I tried both methods, but neither worked... I think I only
need to cast a non-const "v" to a const "v", hence I tried

for(vector<int>::const_reverse_iterator i = v.rbegin(); i !=
(static_cast<const vector<int> >)v.rend(); ++i)
cout << (*i) << endl;

Actually, the cast is a bad idea anyway (I used it only to find the
cause of the problem). Better use a reference to const vector on which
only const member functions can be invoked:

vector<int> v;
// ...
const vector<int>& cv = v; // reference
for(vector<int>::const_reverse_iterator i = cv.rbegin();
i != cv.rend(); ++i)
cout << (*i) << endl;
 
J

Jess

Jess :


Roland Pibinger wrote:
On Sun, 17 Jun 2007 06:45:56 -0700, Jess wrote:
I think the two reverse_iterators are the same, except that the const_
version doesn't allow me to change the value pointed to by the
iterators. However, I have a program that works for reverse_iterator
but not const_reverse_iterator:
for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;
This one fails, with error
no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'
I guess your compiler cannot distinguish between the const and the
non-const rend(). Try:
Seems like it does distinguish between them, and calls the non-const
version on a non-const vector. The problem arises from comparing a
const_iterator to a plain iterator.
for(vector<int>::const_reverse_iterator i = v.rbegin();
i != ((const std::vector<int>) v).rend();
i != ((const std::vector<int>&) v).rend();
That's a minor typo, but critical. As written, it copies the vector,
creating an iterator that points into the copy rather than the original.
Thanks, I tried both methods, but neither worked... I think I only
need to cast a non-const "v" to a const "v", hence I tried
for(vector<int>::const_reverse_iterator i = v.rbegin(); i !=
(static_cast<const vector<int> >)v.rend(); ++i)
cout << (*i) << endl;
Unfortunately, it failed as well

It looks like you are using the wrong syntax. It should be.

i != static_cast<const vector<int>& >(v).rend()

Thanks. I tried but it still doesn't work. Here's the entire
program.

#include<vector>
#include<string>
#include<iterator>
#include<iostream>
using namespace std;

int main(){
vector<int> v;
for(int i = 0; i != 10; ++i)
v.push_back(i);

for(vector<int>::const_reverse_iterator i = v.rbegin(); i !=
static_cast<vector<int>& >(v).rend(); ++i)
cout << (*i) << endl;
return 0;
}

The error message was

no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'

Jess
 
J

Jess

Roland said:
I think the two reverse_iterators are the same, except that the const_
version doesn't allow me to change the value pointed to by the
iterators. However, I have a program that works for reverse_iterator
but not const_reverse_iterator:
for(vector<int>::const_reverse_iterator i = v.rbegin(); i != v.rend();
++i)
cout << (*i) << endl;
This one fails, with error
no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'
I guess your compiler cannot distinguish between the const and the
non-const rend(). Try:

Seems like it does distinguish between them, and calls the non-const
version on a non-const vector. The problem arises from comparing a
const_iterator to a plain iterator.
for(vector<int>::const_reverse_iterator i = v.rbegin();
i != ((const std::vector<int>) v).rend();

i != ((const std::vector<int>&) v).rend();

That's a minor typo, but critical. As written, it copies the vector,
creating an iterator that points into the copy rather than the original.

Thanks Peter, but I don't quite understand this.. Do you mean that if
I don't use the reference, then the program copies the vector and
create an iterator pointing to the copy rather than the original?
Does it happen to all the casting operations? In otherwords, whenever
I do a cast on an object "x" (static_cast or other cast), I can't
modify "x" through the result of the cast? Why is there such
constraint?

Jess
 
J

Jess

Actually, the cast is a bad idea anyway (I used it only to find the
cause of the problem). Better use a reference to const vector on which
only const member functions can be invoked:

vector<int> v;
// ...
const vector<int>& cv = v; // reference
for(vector<int>::const_reverse_iterator i = cv.rbegin();
i != cv.rend(); ++i)
cout << (*i) << endl;

Thanks, this is a very good idea. I'll try to avoid casting. :) To
me, it's quite surprising that I can't use a const function on a non-
const object. The const function promises not to change the object,
so what's wrong with applying the const function on a non-const
object? the function doesn't do any harm to the non-const object.
It's clear why we shouldn't use a non-const function on a const
object, but not so clear the other way round...

Jess
 
P

Pete Becker

Jess said:
To
me, it's quite surprising that I can't use a const function on a non-
const object. The const function promises not to change the object,
so what's wrong with applying the const function on a non-const
object?

There's nothing wrong with it, but when you have a non-const object and
you call a function that's overloaded for const and non-const, you get
the non-const version.

struct S
{
void mf();
void mf() const;
};

void f(S& s, const S& cs)
{
s.mf(); // calls S::mf()
cs.mf(); // calls S::mf() const
((const S&)s).mf(); // calls S::mf() const
}

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
B

BobR

Jess said:
Thanks. I tried but it still doesn't work. Here's the entire
program.

#include<vector>
#include<string>
#include<iterator>
#include<iostream>
// > using namespace std; // Yuck
int main(){
using std::vector;
using std::cout;
using std::endl;
vector<int> v;
for(int i = 0; i != 10; ++i) v.push_back(i);

for(vector<int>::const_reverse_iterator i = v.rbegin(); i !=
static_cast<vector<int>& >(v).rend(); ++i)

Did you try it with the 'const', as suggested?
i != static_cast said:
cout << (*i) << endl;
return 0;
}

The error message was
no match for 'operator!=' in 'i != std::vector<_Tp, _Alloc>::rend()
[with _Tp = int, _Alloc = std::allocator<int>]()'
Jess
 
J

Jess

There's nothing wrong with it, but when you have a non-const object and
you call a function that's overloaded for const and non-const, you get
the non-const version.

struct S
{
void mf();
void mf() const;

};

void f(S& s, const S& cs)
{
s.mf(); // calls S::mf()
cs.mf(); // calls S::mf() const
((const S&)s).mf(); // calls S::mf() const

}

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)


Thanks for clarifying this. Would you please also tell me if it is
true that whenever I do a casting (static_cast or other cast) on an
object, I have to cast to a reference type if I need the object itself
to be changed? If I don't cast the object to a reference type, then I
get a temporary object? I guess internally, if I cast to a reference
type, then no constructor is called, but if I don't cast to a
reference type, then a copy constructor is called...

Jess
 
J

Jess

// > using namespace std; // Yuck

I know this opens up the entire std namespace, but is it still bad if
I use it in my .cpp file?
using std::vector;
using std::cout;
using std::endl;



Did you try it with the 'const', as suggested?

Ah, I forgot the "const in static_cast! Thanks a lot! :)

Jess
 
B

BobR

Jess wrote in message...
I know this opens up the entire std namespace, but is it still bad if
I use it in my .cpp file?

The 'better' way:

The 'best' way:

std::vector<int> vint;

Unless you have a boss dictating the format, it's a style thing - your
choice.
Don't change boats in mid-stream, try to be consistant throughout your
code/project.
Ah, I forgot the "const in static_cast! Thanks a lot! :)
Jess

You're welcome. I assume you "Got 'er done."?
 
J

James Kanze

On Jun 18, 10:23 pm, Pete Becker <[email protected]> wrote:
Thanks for clarifying this. Would you please also tell me if it is
true that whenever I do a casting (static_cast or other cast) on an
object, I have to cast to a reference type if I need the object itself
to be changed? If I don't cast the object to a reference type, then I
get a temporary object? I guess internally, if I cast to a reference
type, then no constructor is called, but if I don't cast to a
reference type, then a copy constructor is called...

Basically, yes, but don't forget that pointers are objects. The
basic rule is that the result is a reference, and the expression
to be converted is an lvalue with a compatible type, there will
be no new object; in all other cases, the result of a cast is a
new object of the target type.

As I said, however, don't forget that pointers are objects. In
something like "static_cast< Base* >( ptrToDerived )", the new
object is the Base*, which however points to the Base part of
whatever object ptrToDerived points to. The only new object is
the pointer.
 
J

Jess

Basically, yes, but don't forget that pointers are objects. The
basic rule is that the result is a reference, and the expression
to be converted is an lvalue with a compatible type, there will
be no new object; in all other cases, the result of a cast is a
new object of the target type.

As I said, however, don't forget that pointers are objects. In
something like "static_cast< Base* >( ptrToDerived )", the new
object is the Base*, which however points to the Base part of
whatever object ptrToDerived points to. The only new object is
the pointer.

Thanks. So if I cast an object to a pointer type or other class type,
but not ref-type, then new an object is always created; in the case of
the pointer,the new object is a pointer that has the same value as the
old pointer hence they point to the same object and we can modify the
object through the new pointer. If I cast the object to a ref-type,
then there is no object created at all, not even the pointer, is this
right?

Thanks,
Jess
 
J

Jerry Coffin

Actually, the cast is a bad idea anyway (I used it only to find the
cause of the problem). Better use a reference to const vector on which
only const member functions can be invoked:

vector<int> v;
// ...
const vector<int>& cv = v; // reference
for(vector<int>::const_reverse_iterator i = cv.rbegin();
i != cv.rend(); ++i)
cout << (*i) << endl;

Of course if that's what you're doing, you really just want:

std::copy(v.rbegin(), v.rend(),
std::eek:stream_iterator<int>(std::cout, "\n"));
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top