std::list iterator: get next element
I'm trying to build a string using data elements stored in a std::list, where I want commas placed only between the elements (ie, if elements are {A,B,C,D} in list, result string should be "A,B,C,D".
This code does not work:
typedef std::list< shared_ptr<EventDataItem> > DataItemList;
// ...
std::string Compose(DataItemList& dilList)
{
std::stringstream ssDataSegment;
for(iterItems = dilList.begin();
iterItems != dilList.e开发者_如何转开发nd();
iterItems++)
{
// Lookahead in list to see if next element is end
if((iterItems + 1) == dilList.end())
{
ssDataSegment << (*iterItems)->ToString();
}
else
{
ssDataSegment << (*iterItems)->ToString() << ",";
}
}
return ssDataSegment.str();
}
How do I get at "the-next-item" in a std::list using an iterator? I would expect that it's a linked-list, why can't I get at the next item?
You cannot do it + N
because you have no random access for list iterators. You can only do one step at a time with list iterators (these are bidirectional iterators).
You can use boost::next
and boost::prior
// Lookahead in list to see if next element is end
if(boost::next(iterItems) == dilList.end())
{
Or you can print the comma before:
std::string Compose(DataItemList& dilList)
{
std::stringstream ssDataSegment;
for(iterItems = dilList.begin();
iterItems != dilList.end();
++iterItems)
{
if(iterItems != diList.begin())
ssDataSegment << ",";
ssDataSegment << (*iterItems)->ToString();
}
return ssDataSegment.str();
}
I believe that a list iterator is bidirectional, but not random access. That means that you can do ++ and -- to it but not add or subtract.
To get the next iterator, make a copy and increment it.
Another solution is to have the first entry be the special case, instead of the last entry:
std::string Compose(DataItemList& dilList)
{
std::stringstream ssDataSegment;
for(iterItems = dilList.begin();
iterItems != dilList.end();
++iterItems)
{
// See if current element is the first
if(iterItems == dilList.begin())
{
ssDataSegment << (*iterItems)->ToString();
}
else
{
ssDataSegment << "," << (*iterItems)->ToString();
}
}
return ssDataSegment.str();
}
You could avoid this problem altogether by using:
std::string Compose(DataItemList& dilList)
{
std::stringstream ssDataSegment;
for(iterItems = dilList.begin(); iterItems != dilList.end(); iterItems++)
{
ssDataSegment << (*iterItems)->ToString() << ","; // always write ","
}
std::string result = ssDataSegment.str();
return result.substr(0, result.length()-1); // skip the last ","
}
You first write the "," for all elements (even for the last one). Than afterwards, you remove the unwanted last "," using substr
. This additionally results in clearer code.
Yet another possibility:
#include "infix_iterator.h"
#include <sstream>
typedef std::list<shared_ptr<EventDataItem> > DataItemList;
std::string Compose(DataItemList const &diList) {
std::ostringstream ret;
infix_ostream_iterator out(ret, ",");
for (item = diList.begin(); item != diList.end(); ++item)
*out++ = (*item)->ToString();
return ret.str();
}
You can get infix_iterator.h from Google's Usenet archive (or various web sites).
Note: Since C++11 you can use std::next and std::prev.
精彩评论