Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Help with std::iterator?

Status
Not open for further replies.

cpjust

Programmer
Sep 23, 2003
2,132
US
OK, I'm usually pretty good at translating this STL nonsense into English, but this time I'm stumped.
How in the world do I use the iterator template?
I want to create my own Directory Iterator class and rather than reinvent the wheel, I wanted to use the STL iterator, but both the MSDN and my books are quite useless. I don't know how to add items into the iterator.
Here's what I have so far:
Code:
class CDirectoryIterator	:	public not_copyable,
								public std::iterator<CDirectoryItem, CDirectoryItem>
{
public:
	CDirectoryIterator( const char*  pszDirectory,
						const char*  pszFileMask			= NULL,
							   bool  searchSubDirectories	= false );

	virtual ~CDirectoryIterator();

private:
	CDirectoryIterator();
};
In the CDirectoryIterator constructor I was thinking of adding the files to the iterator, but I don't see anything that would allow me to do: this->push_back( dirItem );

Also, what are the iterator template parameters used for? Somehow I get the feeling that <CDirectoryItem, CDirectoryItem> isn't quite right. ;)
 
>OK, I'm usually pretty good at translating this STL nonsense into English

Ok, but you semm to have misunderstood how an iterator usually works.

For example you typically don't "add items into the iterator"

You have a collection C of elements E. You have an interator I to access elemens of C.

So, you add your elements/whatever into C and use the I to access them in some manner.

For example look into std::list, std::vector etc and see how they use iterators to point ot where to insert/remove/access elements.

Also note the STL way of getting/declaring the iterators.
Code:
#typedef std::list<Somtype> MyList;
MyList myList;
MyList::iterator it = myList.begin();

What kind of iterator do you have in mind? bi-directaional? random-access? both?

For examples of various (not std inhertied) iterators you could check the iterators section of my
"Introducing Templates, Iterators, and Temporary Classes"
article at

/Per

www.perfnurt.se
 
>Also, what are the iterator template parameters used for? Somehow I get the feeling that <CDirectoryItem, CDirectoryItem> isn't quite right. ;)

Well, the signature is this:
Code:
template<class _C, class _Ty, class _D = ptrdiff_t>
	struct iterator {

Where
_C is the category, bi-directional, random-access etc
_Ty is the value type (ie the element type of the collection)
_D is the the distance type. Ie the type used to determine the distance between elements the iterator is to iterate between.

Btw, I have never had the urge of defining a stand-alnone std derived iterator. The easiest way by far is simply to use a STL collection (which are very generic and can be used for almost anything) and from them get the iterators "for free".

/Per

www.perfnurt.se
 
Thanks, I ended up just deriving from std::list and using its iterator. But I'm still not sure when you would ever need to use std::iterator by itself?

Also, I don't understand why the distance type is needed? Items to be iterated through don't have to be side by side like an array, so the distance between elements is irrelevant isn't it? Besides, wouldn't the distance just be sizeof( _Ty )?
 
cpjust said:
Thanks, I ended up just deriving from std::list
Be careful about this. If you ever try to use your new derived class polymorphically and delete the list pointer then you will get "undefined behavior". There are often better designs than publicly inheriting directly from an STL container.
 
I'm not sure what you mean by "delete the list pointer"? What I'm doing is returning Begin() & End() iterators by returning std::list<CDirectoryItem>::const_iterator
Are there any problems with doing that?
I'm just trying not to reinvent the wheel.
 
It is probably not a big deal for your application, but std::list was not designed to be derived from. The undefined behavior comes here:
Code:
#include <list>

template <typename T>
class MyList : public std::list<T>
{
};

int main()
{
    std::list<int>* pMyList = new MyList<int>;
    delete pMyList;
}
Strictly speaking this is undefined behavior because the std::list class does not have a virtual destructor. In this simple case, and possibly in your case, this won't be a problem in practice.

However, the point is that there might be better designs that are more flexible and robust than simply deriving publicly from std::list. In order to give an opinion as to whether that is true, more information about the problem and your current code would be needed. Some possible alternatives are using contaiment (having an std::list as a member variable), deriving privately from std::list, or just adding global methods that work on a list (or any container).

Based on your initial post my instinct says privately deriving might be the best way to go. But that's just an opinion.
 
No that's fine.

I think uolj took your statement literally, ie that you actually defined a class that inherit from a std::list<Something>.

That's not so good. std thigies are rarely (is ever) meant to be inherited - indicated by that they don't have virtual destructors.

/Per

www.perfnurt.se
 
Actually I am deriving privately from std::list. I didn't want all the list members in the public interface. ;)
 
>Actually I am deriving privately from std::list. I didn't want all the list members in the public interface.

Aha, ok. Well that's not recomended. I'd suggest having it as a member rather than a parent. You can still easily define what to expose without having to re-invent the wheel.

Code:
class MyList
{
  public:
    typedef std::list<whatever> List;
    typedef List::iterator iterator;
    typedef List::const_iterator const_iterator;

    iterator begin() { return mList.begin() }
    // Etc

  private:
   List mList;
};
 ...
{
  MyList myList;
  for (MyList::iterator i=myList.begin(); ... etc))

/Per

www.perfnurt.se
 
I don't think its a big deal to inherit privately. In general, containment is probably better using typedefs and wrapper methods as PerFnurt showed, but private inheritance isn't that much different. I should have specified that I meant public derivation in my original posts.
 
>I don't think its a big deal to inherit privately

You've got a point, but std::list isn't designed to be inherited (as you've already mentioned). Hence I would advice against inherit from it. Period.

>private inheritance isn't that much different

I think it is. The major difference is that you don't have to worry at all about these things.



/Per

www.perfnurt.se
 
Public inheritance is very different than private inheritance. I think (but could be wrong), that the part about std::list not being designed to be inherited from is meant for public inheritance. Other than the designers of C++ and the STL saying so, the reason we know that it is not meant to be derived from is the lack of a virtual destructor. This does not matter in the case of private inheritance, since the base class destructor is not accessible to outside code anyway.

I'll check my references when I get to work to see if they contradict what I'm saying.
 
>I'll check my references when I get to work to see if they contradict what I'm saying.

I'm sure they won't. I bet you're right, technically.

However, I belive that other issues than what is technically possible should be considered. Such as "that you don't have to worry at all about these things".

Hence, I would always advice having it a member rather than as a (private) parent, simply because you'd never have to give it a second thought.
Just as I would always initilize whatever variable to a well-defined value even if it should be assigned one some lines down the code. Technically you could live without it, but still...

Anyway, I guess we could discuss this to eternety (even though I believe we both agree with each other on the whole)... ;-)

/Per

www.perfnurt.se
 
According to my references... The general rule is to use containment over private inheritance unless you need access to protected methods or you need to override virtual functions. In the case of std::list, neither of these are true, so you should prefer containment. Period. ;-)
 
Thanks, I'll try that.

I was just getting stuck on the "is a" vs "has a" design...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top