home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
[an error occurred while processing this directive]
Previous Table of Contents Next


3.  When implementing the new and new[] functions, the easiest way to get them to return memory is to call the global operator ::new[] to allocate an array of char. It is also possible, of course, to call your operating system–specific memory allocation functions. There might be type size issues here; a char is not necessarily one byte on all platforms.
4.  Remember that if you have allocated memory in the new and new[] functions, you must use ::delete[] to free the memory in your delete operators, even on the singular delete function. After all, the memory was allocated by new[], not new. This entire process is hidden from users of the class.

How It Works

The C++ compiler will automatically call the overloaded functions instead of the built-in ones.

Comments

The quality and details of the delete[] and new[] operators vary significantly between compiler vendors. Try running the sample code to see what your compiler generates. All sample listings here are initially compiled with Borland C++, and are tested with DJGPP (a GNU compiler for DOS, including a 32-bit DOS extender). The program leaves the memory statistics in the file memstats.txt, and the results vary between even these two compilers. The following listing shows the memstats.txt file generated by a program compiled with Borland C++ 5.01A. Notice that the bytes allocated and deleted do not match, but the calls do.

 Memory allocation statistics :
  (the numbers below should match)

 Bytes Allocated : 600012
 Bytes Deleted :   300024
 Calls to new :    25001
 Calls to new[] :  1
 Calls to delete : 25001
 Calls to delete[]:1

The following is a memstats.txt file generated by a program compiled with DJGPP using GCC 2.81:

 Memory allocation statistics :
  (the numbers below should match)

 Bytes Allocated : 600016
 Bytes Deleted :   600016
 Calls to new :    25001
 Calls to new[] :  1
 Calls to delete : 25001
 Calls to delete[]:1

As you can see by the output of the programs, the compilers used in this case differed in how they handled the delete operators as well as how they handled the actual size of the Sample_Data class. The difference can be attributed to byte-alignment settings. The GNU compiler seems to default to 8-byte alignment (which is the fastest for Pentium and later processors) in this case, and the Borland compiler seems to default to 4-byte alignment.

However, the compilers seem to agree on array sizes, and align them on 8-byte boundaries.

Code Listings for Chapter 12

The following listing, ex1\newdel.cpp, overloads the new and delete operators:

// File: overnew.cpp
// Example for C++ How-To
// Shows how to overload new and delete to implement a simple memory
// statistics keeper.
// Copyright 1998, Jan Walter
// NO WARRANTY. If this code breaks you get to keep both pieces.

// Compiler verificiation:
// Borland C++ 5.01A:             Yes
// DJGPP 2.01 w. GCC 2.81 :     Yes
// Watcom 10.5:                    Not Tried
// Microsoft VC++ 5:                Not Tried
// GCC 2.7.2/Linux:                Not tried
// GCC/EGCS/Linux:                Not tried

#include <iostream.h>
#include <fstream.h>
#include <stddef.h>

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#include <string>
#include <stdexcept>  // standard exception classes

using namespace std ;

//*********************************************************************
//                Memory statistics class
//*********************************************************************

class MemStats
{
    private:

   unsigned    BytesAllocated ;
   unsigned BytesDeleted ;
   unsigned    CallsToNew ;
   unsigned    CallsToDel ;

   fstream    StatsFile;

   public:

   MemStats() :     BytesAllocated(0), BytesDeleted(0), CallsToNew(0),
                 CallsToDel(0)
   {
      StatsFile.open( “memstats.txt”, ios::out ) ;
       if( !StatsFile )
       throw runtime_error( “Could not open memstats.txt” ) ;
   }

   MemStats( const string& filename ) : BytesAllocated(0), BytesDeleted(0),
                    CallsToNew(0), CallsToDel(0)
   {
      StatsFile.open( filename.c_str() , ios::out ) ;
       if( !StatsFile )
       throw runtime_error( “Could not open user-defined file.” ) ;
    }

   // these functions can be expanded to do all sorts of other things,
   // like print more info into the output file, time and date, etc.
   // or keep track of the allocated chunks of memory in an associative
   // array.

   void newcalled( size_t size )
   {
       CallsToNew++ ;
      BytesAllocated += size ;
   }

   void delcalled( size_t size )
   {
       CallsToDel++ ;
      BytesDeleted += size ;
   }

   ~MemStats()
   {
       StatsFile     << endl
            << “ Memory allocation statistics : ” << endl
            << “  (the numbers below should match)” << endl
            << endl
            << “ Bytes Allocated : ” << BytesAllocated << endl
            << “ Bytes Deleted :   ” << BytesDeleted << endl
            << “ Calls to new :    ” << CallsToNew << endl
            << “ Calls to delete : ” << CallsToDel << endl
            << endl ;
      StatsFile.close() ;     // explicitly close file to make
                  // doubly sure.
   }
} ;

//*********************************************************************

// an interesting side note:
// we cannot easily catch exceptions thrown by the constructor of
// a global object - above the constructor throws a runtime_error
// exception object if it cannot open the file in the constructor.
// If this is true, the program will abort with some message like
// “abnormal program termination” or “Abort!”

MemStats stats ;

//*********************************************************************
//            Sample Data class - nothing special, just an example
//*********************************************************************
class Sample_Data
{

    int     S_int ;
   double S_double ;

   public:

   Sample_Data() : S_int(0), S_double(0.0)
   { }

   Sample_Data( int a, double b = 0.0)
   {
       S_int = a ;
     S_double = b ;
   }

   Sample_Data( double b, int a = 0 )
   {
       S_double = b ;
      S_int = a ;
   }

   Sample_Data( Sample_Data& copyfrom )
   {
       S_int = copyfrom.S_int ;
      S_double = copyfrom.S_double ;
   }

   Sample_Data& operator=( const Sample_Data& copyfrom )
   {
       S_int = copyfrom.S_int ;
      S_double = copyfrom.S_double ;
      return *this ;
   }

   Sample_Data& operator++()
   {
       S_int++ ;
      return *this ;
   }

   void* operator new( size_t size )
   {
       stats.newcalled( size ) ;
      return (void*) ::new char[size] ; // allocate specified number of bytes
                               // with the actual new operator
   }

   void operator delete( void* mem, size_t size )
   {
       stats.delcalled( size );
      ::delete[] mem ;
   }

   // friend functions
   friend ostream& operator<<( ostream& s, const Sample_Data& data );

};

//*********************************************************************

ostream& operator<<( ostream& s, const Sample_Data& data )
   {
       s << data.S_int << ‘ ‘ << data.S_double ;
       return s ;
   }

//*********************************************************************

int main( int, char** )
{
    const int array_size = 50000 ;

    // allocate our sample data
   cout << “Size of Sample_Data: ” << sizeof(Sample_Data) << endl ;
   // declare one object
   Sample_Data a( 50 , 12.555 );

    // instantiate an object dynamically
   Sample_Data* p = new Sample_Data( 21 ) ;

   // declare an array
   Sample_Data* DataArray = new Sample_Data[array_size] ;

   // declare an array of pointers
   Sample_Data* PDataArray[array_size] ;

   // initialize the array
   for (int i = 0 ; i < array_size ; i++ )
       PDataArray[i] = new Sample_Data(i) ;

   // Now work with the data some

   DataArray[0] = a ;

   for( int i = 1; i < array_size ; i++ )
   {
        DataArray[i] = ++DataArray[i-1] ;
       //cout << DataArray[i] << endl ;
   }

   ++*p ;
   cout << *p << endl ;

   // and clean up dynamically allocated stuff.

   delete p ;
   delete[] DataArray ;
   for (int i = 0 ; i < array_size ; i++ )
       delete PDataArray[i] ;

    return 0;
}


// end of file


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.