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;
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());}
};
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;
class CTextBook
{
private:
string m_szTitle;
public:
CTextBook(char* sz):m_szTitle(sz){};
~CTextBook(){printf("%s is completed!\n", m_szTitle.c_str());}
};
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;
CCounterArray cntList;
CAnimalList anList;
char san[20];
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);
}
CCDellocate cntFree;
CADellocate anFree;
cntFree(cntList);
anFree(anList);
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));
}
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.