Click here to Skip to main content
15,867,771 members
Articles / Programming Languages / C++
Article

Using STL algorithm to simplify the code procedure

Rate me:
Please Sign up or sign in to vote.
3.00/5 (4 votes)
26 Feb 20041 min read 42.2K   350   9   4
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


Written By
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalmember template Pin
Anonymous26-Feb-04 22:23
Anonymous26-Feb-04 22:23 
GeneralRe: member template Pin
Anonymous27-Feb-04 13:03
Anonymous27-Feb-04 13:03 
GeneralRe: member template Pin
Anonymous29-Feb-04 20:45
Anonymous29-Feb-04 20:45 
GeneralRe: member template Pin
Zhaohui Xing (Joey)1-Mar-04 5:22
Zhaohui Xing (Joey)1-Mar-04 5:22 
The functor takes more advantages than template function in the STL algorithm application. Please refer to the following sample code about getting the summation of a list. In this sample, the functor is more easier to be adapted than template function. This is why template function can not always kick off functor.

In here, operator TFuncOut(){return m_tSummation;} is very important operator overloading for std::for_each.


template<typename TType, typename TFunc, typename TFuncOut, typename TParam>class TSummation1
{
public:
TSummation1(const TFunc& func, const TParam tParam, const TFuncOut tVal = 0):m_fFunc(func), m_tParam(tParam), m_tSummation(tVal){};

// Overload the operator()
void operator()(TType* t)
{
if(t)
{
m_tSummation += m_fFunc(t, m_tParam);
}
}
operator TFuncOut(){return m_tSummation;}

private:
TFunc m_fFunc; // The member function object
TParam m_tParam; // The member function parameter
TFuncOut m_tSummation; // The return value
};

class CDblCounter
{
private:
double m_dCounter;
public:
CDblCounter(double dVal = 0.0) : m_dCounter(dVal){};
double Calc(double dThreshod)
{
if(dThreshod <= m_dCounter)
{
printf("The counter is %f, larger than or equal to %f\n", m_dCounter, dThreshod);
return m_dCounter;
}
else
{
printf("The counter is %f, smaller than %f\n", m_dCounter, dThreshod);
return 0.0;
}
}
};

typedef vector<CDblCounter*> CDblArray;
typedef mem_fun1_t<double, CDblCounter, double> CDblMemFunc1T;
typedef TSummation1<CDblCounter, CDblMemFunc1T, double, double> CDblSum1Functor;

int _tmain(int argc, _TCHAR* argv[])
{
CDblArray dList1;
CDblCounter* pDbl;

pDbl = new CDblCounter(10.0);
dList1.push_back(pDbl);
pDbl = new CDblCounter(-4.0);
dList1.push_back(pDbl);

pDbl = new CDblCounter(0.0);
dList1.push_back(pDbl);

pDbl = new CDblCounter(30.0);
dList1.push_back(pDbl);

pDbl = new CDblCounter(2.0);
dList1.push_back(pDbl);

pDbl = new CDblCounter(5.0);
dList1.push_back(pDbl);

pDbl = new CDblCounter(-3.0);
dList1.push_back(pDbl);

pDbl = new CDblCounter(7.0);
dList1.push_back(pDbl);

pDbl = new CDblCounter(2.4);
dList1.push_back(pDbl);

pDbl = new CDblCounter(13.7);
dList1.push_back(pDbl);

CDblSum1Functor fSum1(std::mem_fun<double, CDblCounter, double>(&CDblCounter::Calc), 8.0, 0.0);
dSum = for_each(dList1.begin(), dList1.end(), fSum1);
printf(("The summation of the counters which is larger than 8 is %f\n"), dSum);
} ;
}

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.