Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function returning iterator in C++

Tags:

c++

iterator

Following is a Java method that returns an iterator

vector<string> types;

// some code here

Iterator Union::types() 
{
    return types.iterator();
}

I want to translate this code to C++. How can i return an iterator of vector from this method?

like image 630
sufyan siddique Avatar asked Jan 11 '12 16:01

sufyan siddique


5 Answers

This will return an iterator to the beginning of types:

std::vector<string>::iterator Union::types() 
{
    return types.begin();
}

However, the caller needs to know the end() of vector types as well. Java's Iterator has a method hasNext(): this does not exist in C++.

You could change Union::types() to return a range:

std::pair<std::vector<std::string>::iterator, 
          std::vector<std::string>::iterator> Union::types()
{
    return std::make_pair(types.begin(), types.end());
}

std::pair<std::vector<std::string>::iterator, 
          std::vector<std::string>::iterator> p =  Union::types();

for (; p.first != p.second; p.first++)
{
}
like image 82
hmjd Avatar answered Oct 19 '22 13:10

hmjd


You'll want to have a begin and end method:

std::vector<string>::iterator Union::begin()
{
  return types.begin();
}

std::vector<string>::iterator Union::end()
{
  return types.end();
}

For completeness you might also want to have const versions

std::vector<string>::const_iterator Union::begin()const
{
  return types.begin();
}

std::vector<string>::const_iterator Union::end()const
{
  return types.end();
}
like image 30
Sean Avatar answered Oct 19 '22 14:10

Sean


Assuming that types is an attribute of the class Union, a nice, STL compliant, way to handle this is:

class Union
{
std::vector< std::string > types
public:
typedef std::vector< std::string >::iterator iterator;
iterator begin() { return types.begin(); }
iterator end() { return types.end(); }

};
like image 43
ravenspoint Avatar answered Oct 19 '22 14:10

ravenspoint


An union is a container of its members. I would use begin and end to give back iterators to the first and after-the-last members, respectively.

The list of types is not IMO the primary iterable property of an union. So I would myself use the following, and reserve the plain begin and end for the member data itself.

std::vector<string>::const_iterator Union::types_begin() const {
  return types.begin();
}

std::vector<string>::const_iterator Union::types_end() const {
  return types.end();
}
like image 37
Johannes Schaub - litb Avatar answered Oct 19 '22 13:10

Johannes Schaub - litb


Returning an iterator is easy. For example, you can return the first iterator in the vector types:

std::vector<std::string> types;

// some code here

std::vector<std::string>::iterator Union::returnTheBeginIterator() 
{
    return types.begin();
}

Java vs. C++

But C++ iterators are not Java iterators: They are not used the same way.

In Java (IIRC), you have more like an enumerator, that is, you use the method "next" to iterate from one item to the next. Thus, returning the Java iterator is enough to iterate from the begining to the end.

In C++, the iterator is designed to behave like a super-pointer. Thus, it usually "points" to the value, and using the operator ++, --, etc. (depending on the exact type of the iterator), you can move the iterator to "point" to the next, previous, etc. value in the container.

Let's iterate!

Usually, you want to iterate from the beginning to the end.

This, you need to return either the whole collection (as "const", if you want it to be readonly), and let the user iterate the way he/she wants.

Or you can return two iterators, one for the beginning, and one for the end. So you could have:

std::vector<std::string>::iterator Union::typesBegin() 
{
    return types.begin();
}

std::vector<std::string>::iterator Union::typesEnd() 
{
    return types.end();
}

And the, you can iterate from the beginning to the end, in C++03:

// alias, because the full declaration is too long
typedef std::vector<std::string> VecStr ;

void foo(Union & p_union)
{
   VecStr::iterator it = p_union.typesBegin() ;
   VecStr::iterator itEnd = p_union.typesEnd() ;

   for(; it != itEnd; ++it)
   {
       // here, "*it" is the current string item
       std::cout << "The current value is " << *it << ".\n" ;
   }
}

C++11 version

If you provide the full container instead of only its iterators, in C++11, it becomes easier, as you can use the range-for loop (as the foreach in Java and C#):

void foo(std::vector<std::string> & p_types)
{
   for(std::string & item : p_types)
   {
       // here, "item " is the current string item
       std::cout << "The current value is " << item  << ".\n" ;
   }
}

P.S.: Johannes Schaub - litb is right in using the "const" qualifier whenever possible. I did not because I wanted to avoid to dilute the code, but in the end, "const" is your friend.

like image 3
paercebal Avatar answered Oct 19 '22 13:10

paercebal