473,406 Members | 2,620 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

iterate forward OR reverse

I have a class I designed that stores text chat in a
std::vector<sd::string>. This class has a few methods to retrieve these
strings to be displayed on the screen.

void ResetRead( bool Reverse, bool wordWrap ); // Resets iterator. We can
ignore wordwrap for now.
std::string GetLine(); // Reads a line using iterator. Increments
Iterator.

Right now it only works in Reverse, since that's the method I used first,
but now I want to do it using a forward iterator. I want to avoid having to
duplicate code, as iterating forward and reverse are exactly the same with 2
diffeernces.

1. Declare forward iterator or reverse iterator.
2. use .begin() .end() or .rbegin() .rend()

I tried this in a test program:

std::vector<std::string>::iterator* MyIt;
MyIt = (std::vector<std::string>::iterator*) new
std::vector<std::string>::reverse_iterator;
for ( *MyIt = MyVector.begin(); *MyIt != MyVector.end(); ++*MyIt )
std::cout << **MyIt << std::endl;

But it iterators forward anyway. I can see one reason is because I'm using
..begin() and .end() but I would think the program wouldn't work because
++*MyIt on a reverse iterator *should* cause the iterator to go backwards,
which it doesn't. This leads me to believe that even though
reverse_iterator is derived from iterator, it's not using virtual classes,
or something. Not sure.

Can anyone come up with a way to do this without having to declare 2
separate methods for forward reading or reverse reading, or a if block
covering the whole for block?
Jul 23 '05 #1
8 3610
On 2005-07-02, Jim Langston <ta*******@rocketmail.com> wrote:
std::vector<std::string>::iterator* MyIt;
MyIt = (std::vector<std::string>::iterator*) new
std::vector<std::string>::reverse_iterator;
Nooooooo! Don't do that. Iterators are not supposed to be used
runtime-poymorphically.

for ( *MyIt = MyVector.begin(); *MyIt != MyVector.end(); ++*MyIt )
std::cout << **MyIt << std::endl;
Unless operator++ () is virtual, this will call the version in the
base class.

[snip] ++*MyIt on a reverse iterator *should* cause the iterator to go backwards,
which it doesn't. This leads me to believe that even though
reverse_iterator is derived from iterator, it's not using virtual classes,
or something. Not sure.
You only get polymorphic behaviour with virtual functions (NOT "virtual
classes")
Can anyone come up with a way to do this without having to declare 2
separate methods for forward reading or reverse reading, or a if block
covering the whole for block?


Use templates.
template <typename iter>
void printit ( iter start, iter end )
{
for (; start!=end; ++start)
std::cout << *start << std::endl;
}

or you could simplify by using the standard library, and generalise to
allow other ostreams:

template <typename iter>
void printit (iter start, iter end,std::ostream & out = std::cout)
{
std::copy(start,end,std::ostream_iterator(out, "\n"));
}
printit (MyVector.begin(),MyVector.end());
printit (MyVector.rbegin(),MyVector.rend());

Cheers,
--
Donovan Rebbechi
http://pegasus.rutgers.edu/~elflord/
Jul 23 '05 #2

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:hb****************@fe02.lga...
I have a class I designed that stores text chat in a
std::vector<sd::string>. This class has a few methods to retrieve these
strings to be displayed on the screen.

void ResetRead( bool Reverse, bool wordWrap ); // Resets iterator. We can ignore wordwrap for now.
std::string GetLine(); // Reads a line using iterator. Increments
Iterator.

Right now it only works in Reverse, since that's the method I used first,
but now I want to do it using a forward iterator. I want to avoid having to duplicate code, as iterating forward and reverse are exactly the same with 2 diffeernces.

1. Declare forward iterator or reverse iterator.
2. use .begin() .end() or .rbegin() .rend()

I tried this in a test program:

std::vector<std::string>::iterator* MyIt;
MyIt = (std::vector<std::string>::iterator*) new
std::vector<std::string>::reverse_iterator;
for ( *MyIt = MyVector.begin(); *MyIt != MyVector.end(); ++*MyIt )
std::cout << **MyIt << std::endl;
Why do you:

1) Heap allocate the iterator?
2) Type cast the iterator?

To avoid duplicate try use standard algorithm facilities like for_each() and
accumulate():
void MyOp(std::string& o)
{
// play around with o
}

for_each(MyVector.begin(), MyVector.end(), MyOp); // foreward
for_each(MyVector.rbegin(), MyVector.rend(), MyOp); // backward

But it iterators forward anyway. I can see one reason is because I'm using .begin() and .end() but I would think the program wouldn't work because
++*MyIt on a reverse iterator *should* cause the iterator to go backwards,
which it doesn't. This leads me to believe that even though
reverse_iterator is derived from iterator, it's not using virtual classes,
or something. Not sure.

Can anyone come up with a way to do this without having to declare 2
separate methods for forward reading or reverse reading, or a if block
covering the whole for block?

Jul 23 '05 #3

"benben" <be******@hotmail.com> wrote in message
news:42**********************@news.optusnet.com.au ...

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:hb****************@fe02.lga...
I have a class I designed that stores text chat in a
std::vector<sd::string>. This class has a few methods to retrieve these
strings to be displayed on the screen.

void ResetRead( bool Reverse, bool wordWrap ); // Resets iterator. We

can
ignore wordwrap for now.
std::string GetLine(); // Reads a line using iterator. Increments
Iterator.

Right now it only works in Reverse, since that's the method I used first,
but now I want to do it using a forward iterator. I want to avoid having

to
duplicate code, as iterating forward and reverse are exactly the same
with

2
diffeernces.

1. Declare forward iterator or reverse iterator.
2. use .begin() .end() or .rbegin() .rend()

I tried this in a test program:

std::vector<std::string>::iterator* MyIt;
MyIt = (std::vector<std::string>::iterator*) new
std::vector<std::string>::reverse_iterator;
for ( *MyIt = MyVector.begin(); *MyIt != MyVector.end(); ++*MyIt )
std::cout << **MyIt << std::endl;


Why do you:

1) Heap allocate the iterator?
2) Type cast the iterator?

To avoid duplicate try use standard algorithm facilities like for_each()
and
accumulate():
void MyOp(std::string& o)
{
// play around with o
}

for_each(MyVector.begin(), MyVector.end(), MyOp); // foreward
for_each(MyVector.rbegin(), MyVector.rend(), MyOp); // backward


Please see my reply to Donovan. The actual code I am using uses 2 functions
within a class. The code I had shown that you responded to was a test I had
tried to see if I could use iterators as polymorphic.
Jul 23 '05 #4
> Please see my reply to Donovan.

Hmm, I don't see any of your reply to Donovan...or is it in another
discussion?
The actual code I am using uses 2 functions
within a class.
I don't think I understand this. Your actual code was

std::vector<std::string>::iterator* MyIt;
MyIt = (std::vector<std::string>::iterator*) new
std::vector<std::string>::reverse_iterator;
for ( *MyIt = MyVector.begin(); *MyIt != MyVector.end(); ++*MyIt )
std::cout << **MyIt << std::endl;

So what are the 2 functions within what class you are mentioning? My
previous post suggested a better alternative.
The code I had shown that you responded to was a test I had
tried to see if I could use iterators as polymorphic.


Iterators are not guarenteed to be polymorphic. Actually, you don't see many
virtual functions in the STL anyways.

ben
Jul 23 '05 #5

"benben" <be******@hotmail.com> wrote in message
news:42***********************@news.optusnet.com.a u...
Please see my reply to Donovan.
Hmm, I don't see any of your reply to Donovan...or is it in another
discussion?


Here is the reply I was talking about:
"Donovan Rebbechi" <ab***@aol.com> wrote in message
news:sl******************@panix2.panix.com... [SNIP]
Use templates.
template <typename iter>
void printit ( iter start, iter end )
{
for (; start!=end; ++start)
std::cout << *start << std::endl;
}

or you could simplify by using the standard library, and generalise to
allow other ostreams:

template <typename iter>
void printit (iter start, iter end,std::ostream & out = std::cout)
{
std::copy(start,end,std::ostream_iterator(out, "\n"));
}
printit (MyVector.begin(),MyVector.end());
printit (MyVector.rbegin(),MyVector.rend());


I can see how either of these methods would work in the example I had given,
simply outputting the entire vector, but the iterator needs to suvive
between calls.

class CChatBuffer
{
private:
std::vector<std::string>::reverse_iterator r_MIter; // Message Iterator
std::vector<std::string> MessageBuffer; // Buffer to hold messages from
server
public:
void ResetRead( bool Reverse );
std::string GetLine();
// Other class variables/methods not shown
};

void CChatBuffer::ResetRead( bool Reverse )
{
if ( ! Reverse )
r_MIter = MessageBuffer.rend(); // Not allowing forward yet, so set to
end
r_MIter = MessageBuffer.rbegin();
}

std::string CChatBuffer::GetLine()
{
if ( r_MIter != MessageBuffer.rend() )
return (*r_MIter++);
else
return "";
}

I can see also storing iter_start and iter_end in my class (didn't think of
that) and setting them to .rbegin() or .rend() in my ResetRead. I can't
see, however, how I could save the iterator in my class between calls of
GetLine so that GetLine knows if it's a forward or reverse iterator. I
played around with some test code just now but still couldn't figure out how
to do it.

Jul 23 '05 #6

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:DZ****************@fe03.lga...

"benben" <be******@hotmail.com> wrote in message
news:42***********************@news.optusnet.com.a u...
Please see my reply to Donovan.
Hmm, I don't see any of your reply to Donovan...or is it in another
discussion?


Here is the reply I was talking about:
"Donovan Rebbechi" <ab***@aol.com> wrote in message
news:sl******************@panix2.panix.com...
[SNIP]
Use templates.
template <typename iter>
void printit ( iter start, iter end )
{
for (; start!=end; ++start)
std::cout << *start << std::endl;
}

or you could simplify by using the standard library, and generalise to
allow other ostreams:

template <typename iter>
void printit (iter start, iter end,std::ostream & out = std::cout)
{
std::copy(start,end,std::ostream_iterator(out, "\n"));
}
printit (MyVector.begin(),MyVector.end());
printit (MyVector.rbegin(),MyVector.rend());


I can see how either of these methods would work in the example I had

given, simply outputting the entire vector, but the iterator needs to suvive
between calls.

class CChatBuffer
{
private:
std::vector<std::string>::reverse_iterator r_MIter; // Message Iterator
std::vector<std::string> MessageBuffer; // Buffer to hold messages from
server
public:
void ResetRead( bool Reverse );
std::string GetLine();
// Other class variables/methods not shown
};

void CChatBuffer::ResetRead( bool Reverse )
{
if ( ! Reverse )
r_MIter = MessageBuffer.rend(); // Not allowing forward yet, so set to end
r_MIter = MessageBuffer.rbegin();
}

std::string CChatBuffer::GetLine()
{
if ( r_MIter != MessageBuffer.rend() )
return (*r_MIter++);
else
return "";
}

I can see also storing iter_start and iter_end in my class (didn't think of that) and setting them to .rbegin() or .rend() in my ResetRead. I can't
see, however, how I could save the iterator in my class between calls of
GetLine so that GetLine knows if it's a forward or reverse iterator. I
played around with some test code just now but still couldn't figure out how to do it.


Ok, I think I start to understand your problem now.

Basically, you are trying to dynamically reverse the access direction of an
iterator. What is in my mind, is about three different ways of achieving it.
But switching forward and reverse iterator is not a good idea because it is
typically resolved at compile time, not at runtime.

First, std::vector<T>::iterator defines a bidirectional iterator, so you can
use ++ for pointing to the next element, or -- for pointing to the previous
element.

Second, std::vector supports subscription. So using an integer to store the
index can make your class much easier to read and write.

And finally, if applicable, you can merge ResetRead and GetLine, so GetLine
now takes an additional parameter bool reverse.

And worth to note, the iterator returned by calling begin() points to the
first element, end() the ONE PAST the last element; rbegin() the last
element, and rend() the ONE BEFORE the first element.

ben
Jul 23 '05 #7
"benben" <be******@hotmail.com> wrote in message
news:42***********************@news.optusnet.com.a u...

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:DZ****************@fe03.lga...

"benben" <be******@hotmail.com> wrote in message
news:42***********************@news.optusnet.com.a u...
>> Please see my reply to Donovan.
>
> Hmm, I don't see any of your reply to Donovan...or is it in another
> discussion?
Here is the reply I was talking about:
"Donovan Rebbechi" <ab***@aol.com> wrote in message
news:sl******************@panix2.panix.com...
> [SNIP]
> Use templates.
> template <typename iter>
> void printit ( iter start, iter end )
> {
> for (; start!=end; ++start)
> std::cout << *start << std::endl;
> }
>
> or you could simplify by using the standard library, and generalise to
> allow other ostreams:
>
> template <typename iter>
> void printit (iter start, iter end,std::ostream & out = std::cout)
> {
> std::copy(start,end,std::ostream_iterator(out, "\n"));
> }
>
>
> printit (MyVector.begin(),MyVector.end());
> printit (MyVector.rbegin(),MyVector.rend());


I can see how either of these methods would work in the example I had

given,
simply outputting the entire vector, but the iterator needs to suvive
between calls.

class CChatBuffer
{
private:
std::vector<std::string>::reverse_iterator r_MIter; // Message
Iterator
std::vector<std::string> MessageBuffer; // Buffer to hold messages
from
server
public:
void ResetRead( bool Reverse );
std::string GetLine();
// Other class variables/methods not shown
};

void CChatBuffer::ResetRead( bool Reverse )
{
if ( ! Reverse )
r_MIter = MessageBuffer.rend(); // Not allowing forward yet, so set

to
end
r_MIter = MessageBuffer.rbegin();
}

std::string CChatBuffer::GetLine()
{
if ( r_MIter != MessageBuffer.rend() )
return (*r_MIter++);
else
return "";
}

I can see also storing iter_start and iter_end in my class (didn't think

of
that) and setting them to .rbegin() or .rend() in my ResetRead. I can't
see, however, how I could save the iterator in my class between calls of
GetLine so that GetLine knows if it's a forward or reverse iterator. I
played around with some test code just now but still couldn't figure out

how
to do it.


Ok, I think I start to understand your problem now.

Basically, you are trying to dynamically reverse the access direction of
an
iterator. What is in my mind, is about three different ways of achieving
it.
But switching forward and reverse iterator is not a good idea because it
is
typically resolved at compile time, not at runtime.

First, std::vector<T>::iterator defines a bidirectional iterator, so you
can
use ++ for pointing to the next element, or -- for pointing to the
previous
element.


Yes, I know this, but then I would need an if statement to determine weather
to increment or decrement it. I suppose the trinary function would work
though.

return ((reverse)?*r_MIter++:*r_MIter--));

Hmm.. this might work using the storing of the iterator begin and end in
variables. I'll have to test this.

Second, std::vector supports subscription. So using an integer to store
the
index can make your class much easier to read and write.
Doesnt' solve problem of wanting to use as few conditional statements as
possible.
And finally, if applicable, you can merge ResetRead and GetLine, so
GetLine
now takes an additional parameter bool reverse.
I could do this. But dont see how it will help. GetLine is called line by
line, not for the whole vector. It's being used (currently) to display text
to the screen using directx calls, later to write buffer to text file, or
any other thing my program needs to deal with text buffers.
And worth to note, the iterator returned by calling begin() points to the
first element, end() the ONE PAST the last element; rbegin() the last
element, and rend() the ONE BEFORE the first element.


Noted and understood, which is only reason same logic works for both forward
and reverse iterators as long os you use proper .begin() or .rbegin() etc...

thanks, got some testing to do.
Jul 23 '05 #8


Jim Langston schreef:
I have a class I designed that stores text chat in a
std::vector<sd::string>. This class has a few methods to retrieve these
strings to be displayed on the screen.

void ResetRead( bool Reverse, bool wordWrap ); // Resets iterator. We can
ignore wordwrap for now.
std::string GetLine(); // Reads a line using iterator. Increments
Iterator.

Right now it only works in Reverse, since that's the method I used first,
but now I want to do it using a forward iterator. I want to avoid having to
duplicate code, as iterating forward and reverse are exactly the same with 2
diffeernces.
In your code, yes. The generated code is probably slightly more
complex.
E.g. the forward iterator for vector can be a raw pointer, with the
built-in operator++. The reverse_iterator's operator++ definitely can't
be, which means it has to be a class. Of course, this method is usually
inlined so the generated code is the same.

As a result, begin() may return a T* (std::string* in your case)
while rbegin() must return a class.
Can anyone come up with a way to do this without having to declare 2
separate methods for forward reading or reverse reading, or a if block
covering the whole for block?


Refactor the contents of the "whole for block" into a separate
function.
You now have an if-block covering two two-line for-statements (or two
calls to std::for_each( ). Try that too, and see how nice it looks ).

Regards,
Michiel Salters

Jul 23 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

59
by: Raymond Hettinger | last post by:
Please comment on the new PEP for reverse iteration methods. Basically, the idea looks like this: for i in xrange(10).iter_backwards(): # 9,8,7,6,5,4,3,2,1,0 <do something with i> The...
11
by: Milind | last post by:
Hi, I was trying to implement a composition relation, somthing of the following type: class A { public: class B {
15
by: Fady Anwar | last post by:
Hi while browsing the net i noticed that there is sites publishing some software that claim that it can decompile .net applications i didn't bleave it in fact but after trying it i was surprised...
2
by: Lacka | last post by:
Hi, If I have this sequence: Dim dbConnection As System.Data.IDbConnection = New System.Data.SqlClient.SqlConnection(ConfigurationSettings.AppSettings("DB")) Dim dbCommand As...
11
by: Boni | last post by:
Dear all, following code iterates thru the hash table. Dim _Enumerator As IDictionaryEnumerator = _myhashtable.GetEnumerator While _Enumerator.MoveNext() ....
20
by: mike7411 | last post by:
Is there any easy way to reverse the order of the bits in a byte in C++? (i.e. 00000001 becomes 10000000)
41
by: rick | last post by:
Why can't Python have a reverse() function/method like Ruby? Python: x = 'a_string' # Reverse the string print x Ruby: x = 'a_string' # Reverse the string
6
by: shivapadma | last post by:
Result set contains the records of database in forward.But,i want to retrieve records in reverse order. what should i do? please someone help me to solve this problem.
4
by: John A Grandy | last post by:
Is there a performance difference between forward iteration and reverse iteration through a List<string? for ( i = 0; i < myList.Count; i++ ) { // do work, such as forward iterate through a...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.