Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using STL algorithm to simplify the code procedure

0.00/5 (No votes)
26 Feb 2004 1  
The article gives the sample to demonstrate the advantage of using STL algorithm.

Introduction

In the C++ application development, STL algorithm shows extraordinary power to reduce the complexity and size of the code.

This article discusses it with the case of container object buffer release, the simplest application scenario.

Background

The STL container classes are widely used in C++ applications. The task of container object buffer release is not very difficult, but there are a lot of duplicated code being repeated frequently. In this article, a simple design is given out to a way to manage the STL container object buffer release in the case that the container's type is class pointer and allocated by new.

The key step of the design

First, design the deletion template to deal with sequence container, i.e. STL vector, deque, list class.

template<typename TType>class TSeqDeletor
{
public:
    void operator () (TType* ptr)
    {
    if(ptr)
    {
        delete ptr;
    }
    }
};

Second, design the deletion template to deal with associative container, like STL map, set.

template<typename TPair>class TAsoDeletor
{
public:
    void operator () (TPair& tElem)
    {
    if(tElem.second)
    {
        delete tElem.second;
    }
    }
};

Finally, design the function template to implement container buffer release with the STL algorithm:

template<typename TContainer, typename TDelete>class TDealloc
{
public:
    void operator()(TContainer& tc)
    {
    TDelete mdel;
    std::for_each<TContainer::iterator>(tc.begin(), tc.end(), mdel);
    tc.clear();
    }
};
  • TContainer: the container class.
  • TDelete: the deletion functor.

The sample of using the design

The following is the code sample to demonstrate the application of this design:

#include "stdafx.h"

#include "templdefs.h"

#include <vector>

#include <map>

#include <string>


using namespace std;

//The class element for sequence container

class CCounter
{
private:
    int     m_nCounter;
public:
    CCounter(int n = 0):m_nCounter(n){}; 
    ~CCounter(){printf("Counter %i is released!\n", m_nCounter);}
};

class CAnimal
{
private:
    string m_szAnimal;
public:
    CAnimal(char* sz):m_szAnimal(sz){};
    ~CAnimal(){printf("%s is gone!\n", m_szAnimal.c_str());}
};

// The definition of concrete sequence container class and dellocator class

typedef vector<CCounter*>  CCounterArray;
typedef TSeqDeletor<CCounter> CCounerDel;
typedef TDealloc<CCounterArray, CCounerDel> CCDellocate;

typedef vector<CAnimal*>  CAnimalList;
typedef TSeqDeletor<CAnimal> CAnimalDel;
typedef TDealloc<CAnimalList, CAnimalDel> CADellocate;


//The class element for associative container

class CTextBook
{
private:
    string m_szTitle;
public:
    CTextBook(char* sz):m_szTitle(sz){};
    ~CTextBook(){printf("%s is completed!\n", m_szTitle.c_str());}
};

// The definition of concrete associative container class and dellocator class

typedef map<int, CTextBook*> CBookList;
typedef TAsoDeletor<CBookList::value_type> CBookDel;
typedef TDealloc<CBookList, CBookDel> CBDellocate;
typedef pair <int, CTextBook*>  book_pair;

int _tmain(int argc, _TCHAR* argv[])
{
    int i;

    // Demonstrate the sequence container buffer release

    CCounterArray  cntList;
    CAnimalList    anList;
    char           san[20];

    // Create the sequence containers

    for(i = 0; i < 20; i++)
    {
    CCounter* pct = new CCounter(i);
    cntList.push_back(pct);
    }

    for(i = 0; i < 10; i++)
    {
    memset(san, 0, 20);
    sprintf(san, "Animal%i", i);

    CAnimal* pa = new CAnimal(san);
    anList.push_back(pa);
    }

    //Release the sequence container object;

    CCDellocate   cntFree;
    CADellocate   anFree;
    cntFree(cntList);
    anFree(anList);


    // Demonstrate the associative container buffer release

    CBookList      bookList;
    char           szt[40];
    for(i = 0; i < 10; i++)
    {
    memset(szt, 0, 40);
    sprintf(szt, "The Book Title of %i", i);

    CTextBook* pb = new CTextBook(szt);
    bookList.insert(book_pair(i, pb));
    }

    //Release the sequence container object;

    CBDellocate   bookFree;
    bookFree(bookList);

    return 0;
}

The container object buffer release processing is fairly simple in here, just like:

    CCDellocate   cntFree;
    CADellocate   anFree;
    cntFree(cntList);
    anFree(anList);

    CBDellocate   bookFree;
    bookFree(bookList);

If we use the regular way to release the container buffer, code will be like this:

    CCounterArray::iterator citer;
    for(citer = cntList.begin(); citer != cntList.end(); ++citer)
    {
    if((*citer))
        delete (*citer);
    }
    cntList.clear();

    CAnimalList::iterator aiter;
    for(aiter = anList.begin(); aiter != anList.end(); ++aiter)
    {
    if((*aiter))
        delete (*aiter);
    }
    anList.clear();

    CBookList::iterator biter;
    for(biter = bookList.begin(); biter != bookList.end(); ++biter)
    {
    if((*biter).second)
        delete (*biter).second;
    }
    bookList.clear();

Comparing the above two methods, the first design dramatically reduces the code size especially when there are lots of container objects, and the design takes more advantages of OOP.

This article only shows the simplest application case, but the idea presented in this article can be applied on more sophisticated application scenarios and optimize the design.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here