Re: java guy struggling with C++
nthali wrote:
I switched from C++ to java about 5 years ago, and now i'm back doing
some C++.
here's briefly my problem:
I took the C++ stl list class, and tried to wrap it with a
java style List class, and did the same with the iterator.
Why? Java's collection classes embed different basic concepts
than the STL. One can argue about which is better; both have
certain qualities, and definite weaknesses. What one cannot
argue about is which is the idiomatic way of doing something in
the given language. Unless there are very severe constraints
for not doing something the C++ way in C++, it's better not to
fight the language.
Part of (re)learning C++ is learning the idioms necessary to use
the STL effectively.
so my iterator looks
like this:
template <class T>
class Iterator
{
public:
Iterator( List<T> myList )
{
this->myList = myList._list;
started = false;
}
bool hasNext()
{
if ( myList.size() == 0 ) return false;
// for some reason unknown to me, i had to put the .begin()
and .end() check in the same method
// otherwise i get a core dumped.
if ( started == false ) { iter = myList.begin(); started =
true; }
return iter != myList.end();
}
T next()
{
return *iter++;
}
private:
bool started; // why the heck do i have to do this?
Good question. Why? Maybe because you don't initialize iter
in the constructor, like you should.
list<T> myList;
And this line is surely wrong. Your iterator contains a *copy*
of the list, and iterates through this copy. That is definitely
not the C++ way. Nor the Java way.
Note that you also pass the list by copy to the constructor, so
there's no way you can get anything but a copy in the iterator.
The usual C++ use of iterators does not require you to maintain
a reference to the container. It does require you to maintain
two iterators, however: a current position and the end position.
list<T>::iterator iter;
It also requires you to initialize this somehow. (And that's
not really different than in Java. In C++, if you use iter
before initialization, it's undefined behavior; in Java, it will
result in a NullPointerException, but neither corresponds to the
desired behavior.)
};
What's wrong with something like:
template< typename T >
class ListIterator
{
public:
explicit ListIterator( List< T >& list )
: myCurrent( list.asSTLList().begin() )
, myEnd( list.asSTLList().end() )
{
}
bool hasNext() const
{
return myCurrent != myEnd ;
}
T& next()
{
assert( hasNext() ) ;
return *myCurrent ++ ;
}
private:
list< T >::iterator myCurrent ;
list< T >::iterator myEnd ;
} ;
Note that:
1. The list is passed to the constructor by reference, not by
value. (In Java, everything's a pointer. This is not true
in C++, and you only get a level of indirection if you
explicitly request it.)
2. The class itself maintains two iterators. It could also
maintain a pointer to the list, and call end each time, but
why bother?
3. All of the members are initialized in the initialisation
list of the constructor. This is not an absolute necessity;
we could also assign them in the body of the constructor.
But it is a good habit to get into.
4. The constructor needs some way of getting at the underlying
STL list. For demonstration purposes, I used an explicit
member function, but in practice, if I didn't want to expose
the underlying STL list in List, I'd either make
ListIterator a friend of List, so that it could access the
underlying data member, or make List a friend of
ListIterator, then provide a private constructor which took
two std::list<T>::iterator.
5. As written, the class supports copy and assignment, by means
of the compiler generated defaults. If I really wanted to
*enforce* (and not just support) the Java idiom, I'd derive
from an Iterator<T> class, with hasNext() and next()
virtual, and the Iterator<T> class would declare a private
copy constructor and assignment operator, which it didn't
implement (or derive from boost::noncopiable).
template <class T>
class List
{
friend class Iterator;
public:
void add(T obj);
T* get(int i);
int size();
Iterator<T> iterator();
T* toArray();
private:
list<T> _list;
};
The problem i have is: the next() method in the iterator
doesn't really give me the original object in the list, so
changing the values within that object don't change the
original object.
Anyone have any ideas on how to fix this?
Use pass by reference instead of pass by value.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]