Overriding new and delete

M

MJ_India

In my current requirement I want to manage memory of some modules from
a pool.
All the memory allocations (standard and user defined data types) in
these modules must fetch memory from some pool. A memory allocated in
1 module is always freed in same module and is never freed in any
other module.

But I don't know how to override new / delete operator.
1) If I override the definition globally, it overrides the allocation
and deallocation in modules where I want heap memory.

2) If I add extra parameters to new and delete [for ex: void *operator
new(size_t count, bool dummy), void delete(void *where, bool dummy)]
and redefine new to new(true) in required modules.
a) Operator new (and new[]) works fine, but I don't know how to make
the delete work.
b) I don't know if it is standard and would be supported by all C++
compilers.

3) It works fine If I override new/delete in some modules and make
them static. (I tried on Microsoft Visual C++ environment)
But again I don't know if it legal to make new and delete static. (As
they can be either global or defined for a class)

4) I tried to redefine new/delete in a namespace and use that
namespace where I want new definition. But Compiler either ignores it
(when I use "using namespace memory_mngr") or prompt a warning telling
new/delete must be global (When I used memory_mngr::new).

Please help me to find the standard solution for this problem. I want
to use new and delete (and new[], delete[]) in their natural syntax
for all my allocations and deallocations. Thank you in advance.
 
A

Alexander Bartolich

MJ_India said:
[...]
2) If I add extra parameters to new and delete [for ex: void *operator
new(size_t count, bool dummy), void delete(void *where, bool dummy)]
and redefine new to new(true) in required modules.
a) Operator new (and new[]) works fine, but I don't know how to make
the delete work.

You have to call delete as a function, called "operator delete".

void* operator new(size_t size, bool dummy)
{
cout << "new size=" << size << " dummy=" << dummy << '\n';
return malloc(size);
}

void operator delete(void* p, bool dummy)
{
cout << "delete dummy=" << dummy << '\n';
free(p);
}

int main()
{
int* p = new (true) int;
operator delete(p, true);
}
[...]
Please help me to find the standard solution for this problem. I want
to use new and delete (and new[], delete[]) in their natural syntax
for all my allocations and deallocations. Thank you in advance.

There is a fifth option. You can define new/delete as members of class.
 
J

James Kanze

In my current requirement I want to manage memory of some
modules from a pool. All the memory allocations (standard and
user defined data types) in these modules must fetch memory
from some pool. A memory allocated in 1 module is always freed
in same module and is never freed in any other module.
But I don't know how to override new / delete operator.
1) If I override the definition globally, it overrides the
allocation and deallocation in modules where I want heap
memory.
2) If I add extra parameters to new and delete [for ex: void
*operator new(size_t count, bool dummy), void delete(void
*where, bool dummy)] and redefine new to new(true) in required
modules.
a) Operator new (and new[]) works fine, but I don't know how
to make the delete work.
b) I don't know if it is standard and would be supported by
all C++ compilers.

It's standard. Theoretically, the steps you may have to take to
replace new and delete may vary; in practice, it's sufficient to
link you versions in before the library.

Replacing global new and delete, or just adding new placement
new and delete (as you're doing) can be tricky. The main
problem is that a delete expression always calls the
non-placement version, do you need to provide the non-placement
version of operator delete. And since this has to work with the
non-placement operator new as well, you have to replace that was
well. And you have to memorize which allocator or memory pool
was used, in order to know which one to use in the delete; the
classical solution for this is to use some sort of hidden
memory for this, e.g.:

union BlockHeader
{
Allocator* allocator ;
MaxAlignType dummyForAlignment ;
} ;

void*
operator new( size_t n )
{
BlockHeader* p = static_cast< BlockHeader* >(
malloc( n + sizeof( BlockHeader ) ) ) ;
if ( p == NULL ) {
throw std::bad_alloc ;
}
p->allocator = NULL ;
return p + 1 ;
}

void*
operator new( size_t n, Allocator& alloc )
{
BlockHeader* p = static_cast< BlockHeader* >(
alloc.allocate( n + sizeof
( BlockHeader ) ) ) ;
if ( p == NULL ) {
throw std::bad_alloc ;
}
p->allocator = &alloc ;
return p + 1 ;
}

void*
operator delete( void* userPtr )
{
BlockHeader* p = static_cast< BlockHeader* >( userPtr ) - 1 ;
if ( p->allocator == NULL ) {
free( p ) ;
} else {
p->allocator->free( p ) ;
}
}

void*
operator delete( void* userPtr, Allocator& alloc )
{
operator delete( userPtr ) ;
}

(The last is only used if a constructor in the new expression
throws an exception.)

In general, I would try to avoid this solution. If your modules
have distinct classes, you could try using class specific
operator new and delete. Otherwise, named functions can be
used, e.g.:

template< typename T >
T*
create( Allocator& alloc )
{
void* p = alloc.allocate( sizeof( T ) ) ;
try {
return ::new ( p ) T ;
} catch ( ... ) {
alloc.free( p ) ;
throw ;
}
}

template< typename T >
void
destruct( Allocator& alloc, T* obj )
{
obj->~T() ;
alloc.free( obj ) ;
}
3) It works fine If I override new/delete in some modules and make
them static. (I tried on Microsoft Visual C++ environment)
But again I don't know if it legal to make new and delete static. (As
they can be either global or defined for a class)

It's not. They must have external linkage.
4) I tried to redefine new/delete in a namespace and use that
namespace where I want new definition. But Compiler either
ignores it (when I use "using namespace memory_mngr") or
prompt a warning telling new/delete must be global (When I
used memory_mngr::new).

The new and delete operators must be defined at global or class
scope. You can't define them in a namespace.
 
M

MJ_India

MJ_India said:
[...]
2) If I add extra parameters to new and delete [for ex: void *operator
new(size_t count, bool dummy), void delete(void *where, bool dummy)]
and redefine new to new(true) in required modules.
a) Operator new (and new[]) works fine, but I don't know how to make
the delete work.

You have to call delete as a function, called "operator delete".

  void* operator new(size_t size, bool dummy)
  {
    cout << "new size=" << size << " dummy=" << dummy << '\n';
    return malloc(size);
  }

  void operator delete(void* p, bool dummy)
  {
    cout << "delete dummy=" << dummy << '\n';
    free(p);
  }

  int main()
  {
    int* p = new (true) int;
    operator delete(p, true);
  }
Thank you for the quick reply.
1) If I use delete as an operator function call, it won't call
destructor.
2) It is not a natural syntax as per my project requirements.
#define new new(true)
can be done conditionally in configuration to keep the new/new[]
syntax intact. But I found no way to replace delete.
There is a fifth option. You can define new/delete as members of class.
In this case new definitions will be useful to allocate class object
but not for the allocations that would be done inside class member
functions definitions.
 
M

MJ_India

2) If I add extra parameters to new and delete [for ex: void
*operator new(size_t count, bool dummy), void delete(void
*where, bool dummy)] and redefine new to new(true) in required
modules.
a) Operator new (and new[]) works fine, but I don't know how
to make the delete work.
b) I don't know if it is standard and would be supported by
all C++ compilers.

It's standard.  Theoretically, the steps you may have to take to
replace new and delete may vary; in practice, it's sufficient to
link you versions in before the library.

Replacing global new and delete, or just adding new placement
new and delete (as you're doing) can be tricky.  The main
problem is that a delete expression always calls the
non-placement version, do you need to provide the non-placement
version of operator delete.  And since this has to work with the
non-placement operator new as well, you have to replace that was
well.  And you have to memorize which allocator or memory pool
was used, in order to know which one to use in the delete; the
classical solution for this is to use some sort of hidden
memory for this, e.g.:

    union BlockHeader
    {
        Allocator*      allocator ;
        MaxAlignType    dummyForAlignment ;
    } ;

    void*
    operator new( size_t n )
    {
        BlockHeader* p = static_cast< BlockHeader* >(
                            malloc( n + sizeof( BlockHeader ) ) ) ;
        if ( p == NULL ) {
            throw std::bad_alloc ;
        }
        p->allocator = NULL ;
        return p + 1 ;
    }

    void*
    operator new( size_t n, Allocator& alloc )
    {
        BlockHeader* p = static_cast< BlockHeader* >(
                            alloc.allocate( n + sizeof
( BlockHeader ) ) ) ;
        if ( p == NULL ) {
            throw std::bad_alloc ;
        }
        p->allocator = &alloc ;
        return p + 1 ;
    }

    void*
    operator delete( void* userPtr )
    {
        BlockHeader* p = static_cast< BlockHeader* >( userPtr ) - 1 ;
        if ( p->allocator == NULL ) {
            free( p ) ;
        } else {
            p->allocator->free( p ) ;
        }
    }

    void*
    operator delete( void* userPtr, Allocator& alloc )
    {
        operator delete( userPtr ) ;
    }

(The last is only used if a constructor in the new expression
throws an exception.)

In general, I would try to avoid this solution.  If your modules
have distinct classes, you could try using class specific
operator new and delete.  Otherwise, named functions can be
used, e.g.:

    template< typename T >
    T*
    create( Allocator& alloc )
    {
        void* p = alloc.allocate( sizeof( T ) ) ;
        try {
            return ::new ( p ) T ;
        } catch ( ... ) {
            alloc.free( p ) ;
            throw ;
        }
    }

    template< typename T >
    void
    destruct( Allocator& alloc, T* obj )
    {
        obj->~T() ;
        alloc.free( obj ) ;
    }
Thank you for the reply. I hope this will be useful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top