Using STL algorithm to simplify the code procedure





3.00/5 (4 votes)
Feb 27, 2004
1 min read

42794

350
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.