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? 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/
"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?
"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.
> 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
"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.
"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
"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.
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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
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...
|
by: Milind |
last post by:
Hi,
I was trying to implement a composition relation, somthing of the
following type:
class A
{
public:
class B
{
|
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...
|
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...
|
by: Boni |
last post by:
Dear all,
following code iterates thru the hash table.
Dim _Enumerator As IDictionaryEnumerator = _myhashtable.GetEnumerator
While _Enumerator.MoveNext()
....
|
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)
|
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
|
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.
|
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...
|
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
|
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...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
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...
|
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...
|
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,...
|
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...
|
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,...
|
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...
| |