Click here to Skip to main content
6,594,932 members and growing! (15,690 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » STL » General     Intermediate License: The BSD License

A Functor that deletes Pointers from STL Sequence Containers

By Nemanja Trifunovic

A policy based deletion functor that can be used with for_each function.
VC6, VC7, VC7.1, Windows, Visual Studio, STL, Dev
Posted:21 Mar 2004
Views:39,058
Bookmarked:11 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
18 votes for this article.
Popularity: 5.23 Rating: 4.16 out of 5
2 votes, 11.1%
1
1 vote, 5.6%
2

3
3 votes, 16.7%
4
12 votes, 66.7%
5

Introduction

A great thing about STL containers is the way they automatically handle memory for us. By using standard sequence containers such as vector or deque instead of directly dealing with operators new[] and delete[], we avoid possibilities of memory leaks and make our code exception-safe. For instance, if we need a dynamic array of integers within a function, if we use std::vector<int> rather than int*, we would be relieved from worrying about calling delete to free up the memory before we exit the function:

vector<int> vectorArray (30); // the memory will be automatically freed

...
int* oldStyleArray = new int[30]; // be sure to call delete[] oldStyleArray;

However, things get more complicated if we put pointers into a standard container:

struct C
  {
  char data_[50];
  };
  ...
  vector <C*> dataArray;
for (int i = 0; i < 20 ; ++i)
  dataArray.push_back(new C());

After dataArray goes out of scope, only the memory occupied by the pointers itself will be freed, but the objects themselves will stay undeleted unless we do something like:

for (vector <C*>::iterator it = dataArray.begin(), 
  it != dataArray.end(); ++it)
  delete *it;

before dataArray goes out of scope.

The best way to deal with this issue is to never put raw pointers into containers, but to use smart pointers, such as boost::shared_ptr [1], or Loki::SmartPtr [2]:

vector <boost::shared_ptr<C> > dataArray;
for (int i = 0; i < 20 ; ++i)
  dataArray.push_back(boost::shared_ptr<C> (new C()));

Now, we won�t need to care about freeing up the objects.

However, in some instances we still may want to keep raw pointers in STL sequence containers, and in that case we may use some easier way to clean up the memory than hand-writing the loop. One common solution is to write a functor that would give us possibility of using an STL algorithm such as for_each [3].

for_each(dataArray.begin(), dataArray.end(), del_fun<C>());

This approach is better, but it still leaves a lot to be desired. For one thing, it always calls operator delete, which is not appropriate for the cases where the objects are created with new[] or malloc. Also, in some cases we may want to zero the pointers after we delete them.

To address these issues, I implemented a policy-based functor free_ptr.

Design of free_ptr

When using a functor for deleting objects, we are faced with two orthogonal decisions:

  1. Which function to use for deleting objects?
  2. Do we zero the pointers after deletions?

To give the user a choice to make the decisions, I used two separate policies: CleanUpPolicy and ZeroPtrPolicy:

template <typename T, class CleanUpPolicy = DeleteSingleObject, class 
ZeroPtrPolicy = DontZeroPtr>
struct free_ptr : std::unary_function <T*, void>
  {
  void operator()(T*& ptr)
    {
    CleanUpPolicy::Destroy(ptr);
    ZeroPtrPolicy::Zero(ptr);
    }
};

Thanks to the policy-based design, free_ptr is very simple to use, and yet highly customizable. For the most common scenario (single objects created with new, no need to zero pointers), it can be used like this:

for_each(dataArray.begin(), dataArray.end(), free_ptr<C>());

If the objects were created with new[], and we need to zero the pointers after deletion, we write something like:

for_each(dataArray.begin(), dataArray.end(), free_ptr<C, DeleteArray, 
ZeroPtr>());

For the CleanUpPolicy, we have the following choices:

  1. DeleteSingleObject (default) � calls delete for each pointer.
  2. DeleteArray � calls delete[] for each pointer.
  3. Free � calls free() for each pointer.

For the ZeroPtrPolicy, we have two choices:

  1. DontZeroPtr (default) � does nothing.
  2. ZeroPtr - sets each pointer to zero.

In ideal world, we would not even need CleanUpPolicy � if a pointer to a single object was a distinct type than a pointer to array of objects we could have used some template metaprogramming to recognize the right scenario at compile time. However, since this obviously is not the case, I tried to figure out some run-time mechanism to do that. I failed miserably: there does not seem to be a good way to distinguish whether a memory was allocated by new, new[] or malloc if we only have a pointer to this memory. I tried even some non-portable tricks, such as using _memsize to determine the size of the allocated memory block, however, even if we know the amount of allocated memory, it still does not necessarily shows us the number of objects pointed by the pointer. Therefore, the best I could come up with was CleanUpPolicy. One good thing with this solution is that in case of some custom memory-management schema, it would be very easy to write another CleanUpPolicy class and use it as easily as the ones I provided.

I should probably add that usage of free_ptr will not protect you from some bad programming practices. For instance, if you do something like:

vector <C*> dataArray;
dataArray.push_back(new C()); //single object


dataArray.push_back(new C[10]); //array of objects


dataArray.push_back((C*)malloc(sizeof(C))); // malloc-ed object

then free_ptr will not help you. As I said, it is unfortunate that the previous example will compile at all, but this is just another C-legacy that makes C++ less perfect.

Conclusion

I hope that this little article is useful in two ways: it demonstrates policy-based design, a powerful methodology for developing C++ libraries, and it also provides you with a cool little piece of code that you can find useful in your daily programming tasks.

References

License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

Nemanja Trifunovic


Member
Born in Kragujevac, Serbia, and lived there until 2000. Spent four wonderful years in San Diego, California, one year in Boston, one in New York and now lives again in Boston area with his wife and two little daughters.

Wrote his first program in 1984, became a professional developer after he graduated in 1994. After all these years still very passionate about programming and software development in general.
Occupation: Software Developer
Location: United States United States

Other popular STL articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 16 of 16 (Total in Forum: 16) (Refresh)FirstPrevNext
GeneralPrint version of article broken PinmemberMike Rizzi9:14 17 Jul '06  
GeneralRe: Print version of article broken PinmemberNemanja Trifunovic10:16 17 Jul '06  
GeneralSmall bug with for_each Pinmembermsalters23:27 15 Apr '04  
GeneralRe: Small bug with for_each PinmemberNemanja Trifunovic5:52 16 Apr '04  
GeneralRe: Small bug with for_each Pinsussiain_3:58 22 Apr '04  
Generaltogether with Effective STL? Pinmemberseriema15:27 2 Apr '04  
GeneralRe: together with Effective STL? PinmemberNemanja Trifunovic11:24 4 Apr '04  
GeneralSolution that allows map PinmemberSummand11:46 25 Mar '04  
GeneralRe: Solution that allows map PinmemberNemanja Trifunovic12:05 25 Mar '04  
GeneralRe: Solution that allows map PinmemberSummand1:09 26 Mar '04  
GeneralRe: Solution that allows map PinmemberSimon Hughes22:48 28 Mar '04  
GeneralI don't agree with your policy. PinmemberWREY7:35 24 Mar '04  
GeneralRe: I don't agree with your policy. PinmemberNemanja Trifunovic8:13 24 Mar '04  
GeneralFlexibility wins out !! PinmemberWREY10:41 24 Mar '04  
GeneralNice demonstration of policies Pinmemberthought23:20 23 Mar '04  
GeneralRe: Nice demonstration of policies PinmemberNemanja Trifunovic6:05 24 Mar '04  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 21 Mar 2004
Editor: Nishant Sivakumar
Copyright 2004 by Nemanja Trifunovic
Everything else Copyright © CodeProject, 1999-2009
Web16 | Advertise on the Code Project