Return an iterator?

M

Markus Dehmann

I have a class Foo that contains a map<string,string> internally. Now,
I want that users can iterate over the entries in the map. What's the
best way to do that?

I tried a method like
map<string,string>::const_iterator get_const_iterator(){
return my_map.begin();
}
but then users also need to know where the end() of the map is in
order to for-loop over the elements.

So, do I have to provide a begin() and end() method in my Foo class?
Or is there a better solution?

Thanks
Markus
 
D

Daniel T.

I have a class Foo that contains a map<string,string> internally. Now,
I want that users can iterate over the entries in the map. What's the
best way to do that?

I tried a method like
map<string,string>::const_iterator get_const_iterator(){
return my_map.begin();
}
but then users also need to know where the end() of the map is in
order to for-loop over the elements.

So, do I have to provide a begin() and end() method in my Foo class?
Or is there a better solution?

Nope, that's it:

class Class {
map<string, string> my_map;
public:
typedef map<string, string>::const_iterator const_iterator;
const_iterator begin() const {
return my_map.begin();
}
const_iterator end() const {
return my_map.end();
}
};
 
B

Bob Hairgrove

I have a class Foo that contains a map<string,string> internally. Now,
I want that users can iterate over the entries in the map. What's the
best way to do that?

I tried a method like
map<string,string>::const_iterator get_const_iterator(){
return my_map.begin();
}

(BTW this function should be const...you cannot modify the map through
a const_iterator, hence you should be able to call it on const Foo
objects.)
but then users also need to know where the end() of the map is in
order to for-loop over the elements.

So, do I have to provide a begin() and end() method in my Foo class?
Or is there a better solution?

Another (IMHO better) solution would be to provide const access to the
map itself, i.e. a member function such as:

const map<string,string> & the_map() const { return my_map; }
 
D

David Hilsee

[snip]
Another (IMHO better) solution would be to provide const access to the
map itself, i.e. a member function such as:

const map<string,string> & the_map() const { return my_map; }

The begin()/end() approach buys you a little flexibility if you ever decide
to drop std::map to use a different container. In theory, one could replace
the container and provide an iterator that provided the same interface as
std::map::const_iterator. That's not a big deal for small programs, so your
suggestion is probably just as good.
 
S

Siemel Naran

Markus Dehmann said:
I have a class Foo that contains a map<string,string> internally. Now,
I want that users can iterate over the entries in the map. What's the
best way to do that?
So, do I have to provide a begin() and end() method in my Foo class?
Or is there a better solution?

Yes, that's one way as others pointed out. There are 2 other ways I've
used. Though neither way is superior to the others, and I've used all of
them in my own code:

(2) Write a nested class Foo::MapIterator that contains private members
d_begin and d_end pointing to the begin and end of the map. There will be a
functions Foo::MapIterator::valid() const or the like to tell if the
iterator is valid, Foo::MapIterator::eek:perator++() etc.

Foo::MapIterator iter = foo.mapiterator();
for ( ; iter.valid(); ++iter) {
/* do stuff */
}

Unfortunately, in this method you cannot use standard algorithms and others
from boost which expect two iterator arguments. But if you don't need the
generality, then this method is fine.

(3) Provide a template function Foo::for_each_element_in_map.

template <class Oper>
void Foo::for_each_element_in_map(const Oper& oper) {
std::for_each(d_map.begin(), d_map.end(), oper);
}
 
B

Bob Hairgrove

[snip]
Another (IMHO better) solution would be to provide const access to the
map itself, i.e. a member function such as:

const map<string,string> & the_map() const { return my_map; }

The begin()/end() approach buys you a little flexibility if you ever decide
to drop std::map to use a different container. In theory, one could replace
the container and provide an iterator that provided the same interface as
std::map::const_iterator.

I'm not so sure ... map<> is a peculiar beast (behavior of its
operator[] compared to vector::eek:perator[], for example). Clients will
probably want to know the exact type of container they are using,
especially if it's a map.

If you really want to replace the container, you could also provide a
typedef for it and merely change the typedef.
 
R

Richard Herring

Bob Hairgrove said:
[snip]
Another (IMHO better) solution would be to provide const access to the
map itself, i.e. a member function such as:

const map<string,string> & the_map() const { return my_map; }

The begin()/end() approach buys you a little flexibility if you ever decide
to drop std::map to use a different container. In theory, one could replace
the container and provide an iterator that provided the same interface as
std::map::const_iterator.

I'm not so sure ... map<> is a peculiar beast (behavior of its
operator[] compared to vector::eek:perator[], for example). Clients will
probably want to know the exact type of container they are using,
especially if it's a map.

I'd have said it depends entirely on the interface (at the Concept
level) you _choose_ to present to the clients. You may be using a map
internally for your own nefarious purposes, but if you present the data
conceptually to them as a non-modifiable sequence accessible only by
const forward (or maybe bidirectional) iterators, they have no reason to
know or care about the underlying map.
 

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
474,175
Messages
2,570,942
Members
47,489
Latest member
BrigidaD91

Latest Threads

Top