Iterating through List Containers

.

When using containers in a program, I declare a class which represents an item in a container:

// Can also be a struct
class CMyClass : public CObject {
    // Program specific
    ...
};

typedef CTypedPtrList<CPtrList,CMyClass*> TMyList;

Separate class (container) has the actual container object:

class CMyClassList : public CObject {
    private:
        TMyList List;
        // Maybe some other data members too
    public:
        // Usual stuff (construction, destruction etc.)
        void Flush(void);
        BOOL Add(CMyClass *ptr);
        CMyClass *Find(...);
        BOOL Del(...);
};

If the container is associated with a user interface object (tree control, list control etc.), one must iterate through the container and perform an action for each item (or for those that satisfy some criteria). Easy way to do it is to move a List variable to a public part of the class declaration and then access it directly. This is bad since it violates a data encapsulation principle (in all but trivial examples, class declaration has a lot more member variables and methods and performs some useful job too).

One approach is to use a public member function and a supplied callback function which is executed for each item. This is messy since supplied callback function is usually a member function of another class so for each different callback function, class CMyClassList must have an overloaded member function. If a callback function is a static non-member function, one must use a DWORD function argument to pass a "this" pointer to a static callback function, then from within a callback function cast a DWORD to pointer to a class object and then invoke a method which actually performs some action with a container item.

Much easier and more elegant approach is to use special iterator class. New class declaration is slightly modified:

class CMyClassListIterator;

class CMyClassList : public CObject {
    private:
        TMyClassList List;
        // Maybe something else
    public:
        // Usual stuff (construction, destruction etc.)
        void Flush(void);
        BOOL Add(CMyClass *ptr);
        CMyClass *Find(...);
        BOOL Del(...);
    friend CMyClassListIterator;        // New stuff
};

New iterator class is declared as follows:

class CMyClassListIterator : public CObject {
  private:
    CMyClassList& Owner;
    POSITION Pos;
  public:
    CMyClassListIterator(TProcess& obj)
              :CObject(),Owner(obj) { Reset(); }
    void Reset(void)                { Pos = Owner.List.GetHeadPosition(); }
    void Next(void)                 { Owner.List.GetNext(Pos); }
    CMyClass *Current(void)         { return (CMyClass*)Owner.List.GetAt(Pos); }
    BOOL IsDone(void)               { return (Pos == NULL) ? TRUE : FALSE; }
};

Now, all you need to do to iterate thru the list is to implement the following peace of code:

CMyClassList MyList;
........
CMyClassListIterator iterator(MyList);
while (!iterator.IsDone()) {
    CMyClass *ptr = iterator.Current();
    // Use ptr but do not delete it.
    // You can modify its contents however.
    iterator.Next();
};

You can also easily implement a nested iteration. Good side effect of this implementation is that your code for list iteration is focused on the job that must be done since all the code is implemented in one function (no callbacks). Also, data encapsulation is preserved since List object is not directly visible.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Microsoft® Office 365 is a top choice for enterprises that want a cloud-based suite of productivity/ collaboration applications. With Office 365, you get access to Microsoft™ Office solutions practically anytime, anywhere, on virtually any device. It's a great option for current Microsoft users who can now build on their experience with Microsoft™ solutions while enjoying the flexibility of a cloud-based delivery. But even organizations with no previous investment in Microsoft will find that …

  • Live Event Date: July 28, 2016 @ 1:00 p.m. ET / 10:00 a.m. PT Jepsen tests are third-party tests for distributed databases that validate vendors' guarantees about how they perform under various failure scenarios, especially network partitions. These have proven their value as tools in any distributed system tester's arsenal. When the creator of Jepsen, Kyle Kingsbury, started his Jepsen-for-Hire business last fall, VoltDB immediately got in line, and over the past two months, our solution was given the most …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date