dcsimg

Iterating through List Containers

WEBINAR:
On-Demand

Application Security Testing: An Integral Part of DevOps


.

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

  • How to erase an item while iterating?

    Posted by Legacy on 05/06/2003 12:00am

    Originally posted by: Cristian Hudici

    Good article! I have a question that would complete it. What happens if somebody needs to erase one (or more) element(s) of the list, while iterating? Does this make the iterator instable? I think so. And more importantly, what's the solution?

    Reply
  • My version...

    Posted by Legacy on 04/16/2000 12:00am

    Originally posted by: Jeff Miller

    I like my way better, but much thanks goes to the original author for the idea.  This sample is for use with a CObList contained within a CDocument.  Modify as appropriate.
    
    

    class CSearchResultsIterator : public CObject
    {
    public:

    CSearchResultsIterator( const CMcatDoc* pDoc ) :
    CObject(),
    m_pDoc( pDoc ),
    m_pos( NULL )
    {
    ASSERT( m_pDoc != NULL );
    Reset();
    }

    void Reset( void )
    {
    m_pos = m_pDoc->m_listSearchResults.GetHeadPosition();
    }

    BOOL GetNext( const CMFile*& Mfile )
    {
    // returns FALSE if this is the last item

    if ( m_pos )
    {
    CObject* pObj = m_pDoc->m_listSearchResults.GetNext( m_pos );

    Mfile = STATIC_DOWNCAST( CMFile, pObj );
    }

    return ( m_pos != NULL );
    }

    int GetCount( void ) const
    {
    return m_pDoc->m_listSearchResults.GetCount();
    }

    private:

    const CMcatDoc* m_pDoc;
    POSITION m_pos;
    };

    Reply
  • good piece!!!

    Posted by Legacy on 10/28/1999 12:00am

    Originally posted by: B.Banerjee

    Congrats!! It is a good piece of code. It will be of definite use to me.

    Reply
  • pretty nice

    Posted by Legacy on 05/11/1999 12:00am

    Originally posted by: Andy Young

    I like the manipulation of inline, and the ingenuity of direct access, if tedious while coding it, to maintain private, encapsulated data.

    Reply
  • member of type CMyPropSheet

    Posted by Legacy on 04/30/1999 12:00am

    Originally posted by: Martin Speiser

    Hi Bill,

    do your dialog class has a member of type CMyPropSheet? In this case the constructor of the sheet will be called during construction of the dialog class.

    Martin

    Reply
  • I wish my code was peaceful, too.. ;-)

    Posted by Legacy on 11/02/1998 12:00am

    Originally posted by: Christian Laforte

    Interesting article! Thanks!

    Reply
  • You must have javascript enabled in order to post comments.

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

Top White Papers and Webcasts

  • Discover the best practices from HPE’s IT Advisory Consulting Services for migrating and transforming applications in Hybrid IT by capitalizing on innovative platforms, modern application architectures, agile development tools and proven methodologies. There are a number of challenges our customers face when migrating and transforming applications for a Hybrid IT environment. This guide provide proven strategies and application approaches that can help them understand and reduce risks and complexity.

  • CEOs, CIOs, boards and shareholders are demanding digital transformation. They want their organizations to be more customer-focused, competitive and strategic to increase revenue. Data drives all of those aspects. A great first step in optimizing data use is moving data to the cloud. It can quickly show benefits. Here are six aspects of a cloud data management strategy that will help your organization more fully move, manage and use valuable data to successfully support digital transformation.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date
×
We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.