We help IT Professionals succeed at work.

stl clear or erase ?

zizi21
zizi21 asked
on
hi,

i have finished using a structure and i want to free memory.
i read that stl does automatically memory freeing.

could i free it myself. would stl clear or erase work ? thanks
Comment
Watch Question

If you allocated the structure using the "new" operator, then you need to deallocate the structure using the "delete" operator.

How, explicitly, did you allocate memory for the structure?
Kent OlsenData Warehouse / Database Architect
Commented:
Hi zizi,

C has no mechanism for automatically freeing memory.  C++ does.

In C, if you allocate it you'll need to free it if you want to reuse the memory.


Good Luck,
Kent
Hi zizi,

I just noticed (clued in by kdo) that you chose the c-zone but your question is c++. Now that I think of it, you have asked a number of questions in the c-zone that were about vectors, etc. - this can cause some confusion.

I am assuming from your question that you are looking for a c++ response.

Regards,
    Paul

Author

Commented:
sorry, it is for c++

Author

Commented:
the memory was allocated using push_back
If using push_back, then you do not want to use delete.
Since you are dealing with structures, I am assuming that you are using vector to hold the structures (call it vec).

vec.clear() - results in wiping out all the elements in the vector resulting in a vec.size() returning 0.
      http://www.cplusplus.com/reference/stl/vector/clear/

vec.erase() - results in one or more specified vector elements to be removed
    http://www.cplusplus.com/reference/stl/vector/erase/

But deallocation to free memory by these commands are not done on demand. The structures destructor is called for each removal, and if that destructor has some delete(s) in it because a structure's member was a pointer that was allocated with a new, then you will get some freeing of memory.
The clear and erase, while they can cause the vec.size() value returned to be less than before the operation, does not necessarily cause memory to be freed.
If you want to force control of deallocation of memory for vector, take a look at:
     http://www.cplusplus.com/reference/std/memory/allocator/deallocate/
     http://www.cplusplus.com/reference/std/memory/allocator/allocate/
and a code example taken from:
     http://www.cplusplus.com/reference/stl/vector/get_allocator/
     

// vector::get_allocator
#include <iostream>
#include <vector>

using namespace std;

int main ()
{
  vector<int> myvector;
  int * p;
  unsigned int i;

  // allocate an array of 5 elements using vector's allocator:
  p=myvector.get_allocator().allocate(5);

  // assign some values to array
  for (i=0; i<5; i++) p[i]=i;

  cout << "The allocated array contains:";
  for (i=0; i<5; i++) cout << " " << p[i];
  cout << endl;

  myvector.get_allocator().deallocate(p,5);

  return 0;
}

Open in new window

Author

Commented:
thanks a million..
I didn't mean for you to close this just yet. I suspect there are still going to be usage issues.

Author

Commented:
yeah, your suspection is true. there is usage issues.  i can't use this because i need to use push_back...and at that time, i don't really know how much i need.  
I think a future version of C++ (C++0x ) may have a real shrink_to_fit method. I see that MSDN already has it:
    http://msdn.microsoft.com/en-us/library/dd647619.aspx

For reference, please look at:
vector::capacity Return size of allocated storage capacity
    http://www.cplusplus.com/reference/stl/vector/capacity/

Ref:     http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=434
"Shrink To Fit
If clear() doesn't cause vector to shrink (i.e., reduce its capacity), is there an alternative technique for shrinking a vector? In C++98 and C++03 the common idiom is to swap the container with a temporary empty container of the same type and the desired size: (I modified their code to show allocations + oddly enough, their code worked in Visual Studio, but got error compiling in Cygwin; so I went back to basics...)

OUTPUT:
$ ./a
bufcapacity 1 = 10000000
bufcapacity 2 = 10000000
bufcapacity 3 (tmp)= 0
bufcapacity 4 = 0
bufcapacity 5 (tmp) = 10000000

But using this swap approach, I got rid of the large tmp vector by defining tmp within { } so that when the } is reached, the tmp destructor is called to eliminate tmp. You can achieve similar results using new vector<> and then delete it. I verified that in both Visual Studio and Cygwin, the allocated memory for the executable decreases significantly when the right } is executed.

Time permitting, I'll look into the allocation approach noted in previous post where you can use push_back.
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main ()
{
   vector<int> myvector;

   vector<char> client_sms_buffer(10000000);
   client_sms_buffer.clear();
   int bufcapacity = client_sms_buffer.capacity();
   cout << "bufcapacity 1 = " << bufcapacity << endl;

   client_sms_buffer.resize(161); // no storage is allocated here
   bufcapacity = client_sms_buffer.capacity();
   cout << "bufcapacity 2 = " << bufcapacity << endl;

   { // START A NEW BLOCK HERE SO THAT tmp WILL GO OUT OF SCOPE
      vector<char> tmp;
      bufcapacity = tmp.capacity();
      cout << "bufcapacity 3 (tmp)= " << bufcapacity << endl;

      client_sms_buffer.swap(tmp); //shrink to zero capacity
      bufcapacity = client_sms_buffer.capacity();
      cout << "bufcapacity 4 = " << bufcapacity << endl;
      bufcapacity = tmp.capacity();
      cout << "bufcapacity 5 (tmp) = " << bufcapacity << endl;
   } // tmp goes out of scope

   return 0;
}

Open in new window

Hi zizi,
You mentioned using clear(), so let's go over this easy case.
As the link indicates (http://www.cplusplus.com/reference/stl/vector/clear/) after the clear() call, size() returns 0; so you wiped out all the content of the vector without deallocating the memory. (This is considered an optimization in STL.) As noted above, if your execution takes you outside of the block { } where your vector is defined, then the vector is deallocated (after your structure destructor are called) and your memory is freed up.

If you call clear() and want all the memory freed, you can define a pointer to the vector and just new the vector. Then after you call clear(), you can just delete the vector. But if going that far, then you probably do not need to call clear since the vector destructor will be called anyway. So, here is some code that illustrates again (on VS 2008 Express) that the clear did no deallocation. But I confirmed with the task manager that after the delete, the program released the memory.

OUTPUT:
bufcapacity 1 = 10000000
bufcapacity 2 = 10000000

As far as erase goes, I'll take a look tomorrow.
#include <iostream>
#include <vector>
using namespace std;

int main ()
{
   vector<char> *client_sms_buffer = new vector<char>(10000000);
   client_sms_buffer->clear();
   int bufcapacity = client_sms_buffer->capacity();
   cout << "bufcapacity 1 = " << bufcapacity << endl;

   client_sms_buffer->resize(161); // no storage is allocated here
   bufcapacity = client_sms_buffer->capacity();
   cout << "bufcapacity 2 = " << bufcapacity << endl;
   delete client_sms_buffer;
   return 0;
}

Open in new window

Definitely last call for the night. Another swap approach that doesn't require the extra explicit tmp vector within a block { }.
     vector<char>(client_sms_buffer).swap(client_sms_buffer);

See if this swap works for your program.

OUTPUT:
After clear
myVect.capacity() 1 = 10000000

After push_back
HelloWorlds
capacity = 10000000  size = 11

After pop_back
HelloWorld
capacity = 10000000  size = 10

After erase last
HelloWorl
capacity = 10000000  size = 9

After swap:
HelloWorl
capacity = 9  size = 9

After erase
HeoWorl
capacity = 9  size = 7

After swap:
HeoWorl
capacity = 7  size = 7


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

#define PRINT_VECT(str) cout << endl << str << endl; \
   for(size_t i=0; i<myVect.size(); i++ ) \
   { cout << myVect[i]; }  \
     cout << endl; \
     cout << "capacity = " << myVect.capacity() \
          << "  size = " << myVect.size() << endl;

int main ()
{
   vector<char> myVect(10000000);
   char Hello[] = "HelloWorlds";
   myVect.clear();
   cout << "After clear" << endl;
   cout << "myVect.capacity() 1 = " << myVect.capacity() << endl;

   for( int k=0; k<sizeof(Hello)-1; k++ ) {
      myVect.push_back(Hello[k]);
   }

   PRINT_VECT("After push_back");

   // pop_back
   myVect.pop_back();
   PRINT_VECT("After pop_back");

   // ERASE
   myVect.erase(myVect.end()-1);
   PRINT_VECT("After erase last");

   vector<char>(myVect).swap(myVect);
   PRINT_VECT("After swap:");

   // ERASE
   myVect.erase( myVect.begin() + 2, myVect.begin() + 4);
   PRINT_VECT("After erase");

   vector<char>(myVect).swap(myVect);
   PRINT_VECT("After swap:");

   return 0;
}

Open in new window

Forgot to give you a vector swap reference:
     http://www.cplusplus.com/reference/stl/vector/swap/

Forgot to give you a CAVEAT taken from The C++ Standard Library: A Tutorial and Reference - Nicolai M. Josuttis

"Because the capacity of vectors never shrinks, it is guaranteed that references, pointers, and iterators remain valid even when elements are deleted or changed, provided they refer to a position before the manipulated elements. However, insertions may invalidate references, pointers, and iterators.

"There is a way to shrink the capacity indirectly: Swapping the contents with another vector swaps the capacity. The following function shrinks the capacity while preserving the elements:

   template <class T>
    void shrinkCapacity(std::vector<T>& v)
    {
         std::vector<T> tmp(v);    // copy elements into a new vector
         v.swap(tmp);              // swap internal vector data
    }

"You can even shrink the capacity without calling this function by calling the following statement:
   //shrink capacity of vector v for type T
   std::vector<T>(v).swap(v);

"However, note that after swap(), all references, pointers, and iterators swap their containers. They still refer to the elements to which they referred on entry. Thus, shrinkCapacity() invalidates all references, pointers, and iterators."

This last statement is the CAVEAT. But the last piece of code (that does not use the tmp) has its own CAVEAT:
"You (or your compiler) might consider this statement as being incorrect because it calls a nonconstant member function for a temporary value. However, standard C++ allows you to call a nonconstant member function for temporary values."