overloading new/delete operator

J

jstachera

I have overloaded new and delete (here is the full post):

Code Block 1
<code>
inline void* operator new(size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}

inline void operator delete(void* deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}

inline void* operator new [](size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}

inline void operator delete[](void * deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
</code>

new operator is called without any problems, eg.:

Code Block 2

<code>
template<typename T>
T*** NMap<T>::alloc3DArray(int c, int sx, int sy) {
T*** data = new T**[c];
mem_begin_ = new T[c*sx*sy];
T* tmp;

for (int i = 0; i < c; i++) {
tmp = (mem_begin_ + i*sx*sy);
data = new T*[sy];
for (int y = 0; y < sy; y++) {
data[y] = (tmp + y*sx);
}
}
allocated++;
return data;
}
</code>

but the delete operator is called from somewhere else (it is not
called the one that is defined by me [Code block 1]):

Code Block

<code>
template<typename T>
void NMap<T>::free3DArray(T*** data, int c) {
for (int i = 0; i < c; i++) {
T** d = data; //some external delete
delete[] d;
}
delete[] data;

delete[] mem_begin_;
deallocated++;
}
</code>

where is the problem ???

I use in my project some static libraries and one of them contains
definitions of new/delete operators:

Code Block

<code>
// Custom memory allocator
namespace nv {
namespace mem {
NVCORE_API void * malloc(size_t size);
NVCORE_API void * malloc(size_t size, const char * file, int
line);

NVCORE_API void free(const void * ptr);
NVCORE_API void * realloc(void * ptr, size_t size);

} // mem namespace

} // nv namespace


// Override new/delete
inline void * operator new (size_t size) throw() {
return nv::mem::malloc(size);
}

inline void operator delete (void *p) throw() {
nv::mem::free(p);
}

inline void * operator new [] (size_t size) throw() {
return nv::mem::malloc(size);
}

inline void operator delete [] (void * p) throw() {
nv::mem::free(p);
}
</code>

When I put in my code non-inline version of new and delete:

Code Block

<code>
void* operator new(size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}

void operator delete(void* deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}

void* operator new [](size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}

void operator delete[](void * deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
</code>


I got following linker errors (they don't appear if I precede my new/
delete definitions by inline keyword - but it still does not work):

------ Build started: Project: BTC_TC, Configuration: Debug Win32
------
Compiling...
Config.cpp
main.cpp
Generating Code...
Compiling manifest to resources...
Linking...
LINK : C:\Documents and Settings\indy\Moje dokumenty\Visual Studio
2005\Projects\NMHaar\Debug\BTC_TC.exe not found or not built by the
last incremental link; performing full link
nvcore.lib(StrLib.obj) : error LNK2005: "void * __cdecl operator
new(unsigned int)" (??2@YAPAXI@Z) already defined in main.obj
nvcore.lib(Memory.obj) : error LNK2005: "void * __cdecl operator
new(unsigned int)" (??2@YAPAXI@Z) already defined in main.obj
nvcore.lib(Debug.obj) : error LNK2005: "void * __cdecl operator
new(unsigned int)" (??2@YAPAXI@Z) already defined in main.obj
nvimage.lib(Quantize.obj) : error LNK2005: "void * __cdecl operator
new(unsigned int)" (??2@YAPAXI@Z) already defined in main.obj
nvimage.lib(Quantize.obj) : error LNK2005: "void * __cdecl operator
new[](unsigned int)" (??_U@YAPAXI@Z) already defined in main.obj
nvimage.lib(Image.obj) : error LNK2005: "void * __cdecl operator
new(unsigned int)" (??2@YAPAXI@Z) already defined in main.obj
nvimage.lib(ImageIo_Obj) : error LNK2005: "void * __cdecl operator
new(unsigned int)" (??2@YAPAXI@Z) already defined in main.obj
nvimage.lib(ImageIo_Obj) : error LNK2005: "void * __cdecl operator
new[](unsigned int)" (??_U@YAPAXI@Z) already defined in main.obj
Creating library C:\Documents and Settings\indy\Moje dokumenty
\Visual Studio 2005\Projects\NMHaar\Debug\BTC_TC.lib and object C:
\Documents and Settings\indy\Moje dokumenty\Visual Studio 2005\Projects
\NMHaar\Debug\BTC_TC.exp
C:\Documents and Settings\indy\Moje dokumenty\Visual Studio
2005\Projects\NMHaar\Debug\BTC_TC.exe : fatal error LNK1169: one or
more multiply defined symbols found
Build log was saved at "file://c:\Documents and Settings\indy\Moje
dokumenty\Visual Studio 2005\Projects\NMHaar\NMHaar\Debug
\BuildLog.htm"
BTC_TC - 9 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped
==========

How can I disable the new/delete operators from static libraries ??
 
J

James Kanze

I have overloaded new and delete (here is the full post):

No you haven't. You've replaced the global new and delete
operators. But with something that isn't legal, giving
undefined behavior.
Code Block 1
<code>
inline void* operator new(size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}
inline void operator delete(void* deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
inline void* operator new [](size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}
inline void operator delete[](void * deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
</code>

The global new and delete operators (at least the standard
forms) are not allowed to be defined inline.
new operator is called without any problems, eg.:
Code Block 2
<code>
template<typename T>
T*** NMap<T>::alloc3DArray(int c, int sx, int sy) {
T*** data = new T**[c];
mem_begin_ = new T[c*sx*sy];
T* tmp;

for (int i = 0; i < c; i++) {
tmp = (mem_begin_ + i*sx*sy);
data = new T*[sy];
for (int y = 0; y < sy; y++) {
data[y] = (tmp + y*sx);
}
}
allocated++;
return data;
}
</code>

but the delete operator is called from somewhere else (it is not
called the one that is defined by me [Code block 1]):
Code Block

<code>
template<typename T>
void NMap<T>::free3DArray(T*** data, int c) {
for (int i = 0; i < c; i++) {
T** d = data; //some external delete
delete[] d;
}
delete[] data;

delete[] mem_begin_;
deallocated++;
}
</code>

where is the problem ???

Well, first, you have undefined behavior, because you've defined
your replacement new and delete operators inline. Then, you go
out of your way to ensure that the undefined behavior will cause
problems, by using templates, so you don't know where what will
be allocated or deleted.

The question is what you really want to do:

-- If you really want to replace the global new and delete, it
should be sufficient to put your functions in a source file,
compile it, and link it in before the standard C++ library.
(The standard doesn't say this---it doesn't say anything
about *how* you compile and link. But this works for all
compilers I've ever seen: Sun CC, g++, xlC, VC++...).
Generally, however, this is a bad idea, except for global
debugging versions of the operators.

-- If you only want certain classes (or templates) to use your
operators, make them members of the class.

-- If you only want them used in the functions above, give them
different names, and separate allocation from
initialization, like the STL does, i.e.: instead of
p = new T ;
use
p = static_cast< T* >( allocate( sizeof( T ) ) ) ;
new ( p ) T ;
and instead of:
delete p ;
use
p->~T() ;
free( p ) ;

(Obviously, you don't want to do this generally, or require
client code to do it. But it works well when localized in a
specific class or template.)

-- If you want to offer a choice at the allocation point, use
placement new, i.e. define a new operator which takes an
additional argument telling you how to allocate.

Note that if you do this, you will have to replace the
global new and delete as well: since the delete expression
does not call your placement delete, you have to somehow
save the information which new was used, and exploit it in
the global delete to choose which delete to use.
I use in my project some static libraries and one of them contains
definitions of new/delete operators:
Code Block
<code>
// Custom memory allocator
namespace nv {
namespace mem {
NVCORE_API void * malloc(size_t size);
NVCORE_API void * malloc(size_t size, const char * file, int
line);

NVCORE_API void free(const void * ptr);
NVCORE_API void * realloc(void * ptr, size_t size);

} // mem namespace
} // nv namespace
// Override new/delete
inline void * operator new (size_t size) throw() {
return nv::mem::malloc(size);
}
inline void operator delete (void *p) throw() {
nv::mem::free(p);
}
inline void * operator new [] (size_t size) throw() {
return nv::mem::malloc(size);
}
inline void operator delete [] (void * p) throw() {
nv::mem::free(p);
}
</code>

Again, this is illegal, and results in undefined behavior. If
you wrote the libraries, correct them. If you didn't, don't use
them; they cannot be made to work correctly, except by chance.
When I put in my code non-inline version of new and delete:
Code Block
<code>
void* operator new(size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}
void operator delete(void* deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
void* operator new [](size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}
void operator delete[](void * deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
</code>
I got following linker errors (they don't appear if I precede
my new/ delete definitions by inline keyword - but it still
does not work):

You have undefined behavior as soon as any standard operator new
or operator delete is declared inline. Anything can happen.

[...]
How can I disable the new/delete operators from static libraries ??

Don't provide a standard global new/delete operator in a
library. Ever. A library which requires a non-standard version
of operator new or operator delete is simply unusable. Period.
 
J

jstachera

No you haven't. You've replaced the global new and delete
operators. But with something that isn't legal, giving
undefined behavior.
<code>
inline void* operator new(size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}
inline void operator delete(void* deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
inline void* operator new [](size_t size) throw() {
return TC::MemoryPoolManager::getInstance().allocateMemory(size);
}
inline void operator delete[](void * deletable, size_t size) throw() {
TC::MemoryPoolManager::getInstance().releaseMemory(deletable,
size);
}
</code>

The global new and delete operators (at least the standard
forms) are not allowed to be defined inline.

Ok, let's assume that there was no keyword inline and my definitions
of
new/delete operators are placed in source file -> it still does not
work.
I use Visual Studio 2005, and for new it works correctly, but when it
comes
to call delete some external delete is called (provided by MS).
Previously I had a problem with static library with global definition
of new/delete
and now I have problem with this (this is called when i use delete in
my code):

C:\ <microsoft visual studio dir>\VC\crt\src\delete2.cpp

/***
*delete2.cpp - defines C++ vector delete routine
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Defines C++ delete routine.
*
*******************************************************************************/

#include <cruntime.h>
#include <malloc.h>
#include <new.h>
#include <windows.h>
#include <rtcsup.h>

void operator delete[]( void * p )
{
RTCCALLBACK(_RTC_Free_hook, (p, 0))

operator delete(p);
}

new operator is called without any problems, eg.:
Code Block 2
<code>
template<typename T>
T*** NMap<T>::alloc3DArray(int c, int sx, int sy) {
T*** data = new T**[c];
mem_begin_ = new T[c*sx*sy];
T* tmp;
for (int i = 0; i < c; i++) {
tmp = (mem_begin_ + i*sx*sy);
data = new T*[sy];
for (int y = 0; y < sy; y++) {
data[y] = (tmp + y*sx);
}
}
allocated++;
return data;
}
</code>
but the delete operator is called from somewhere else (it is not
called the one that is defined by me [Code block 1]):
Code Block

<code>
template<typename T>
void NMap<T>::free3DArray(T*** data, int c) {
for (int i = 0; i < c; i++) {
T** d = data; //some external delete
delete[] d;
}
delete[] data;

delete[] mem_begin_;
deallocated++;
}
</code>
where is the problem ???

Well, first, you have undefined behavior, because you've defined
your replacement new and delete operators inline. Then, you go
out of your way to ensure that the undefined behavior will cause
problems, by using templates, so you don't know where what will
be allocated or deleted.

The question is what you really want to do:

-- If you really want to replace the global new and delete, it
should be sufficient to put your functions in a source file,
compile it, and link it in before the standard C++ library.
(The standard doesn't say this---it doesn't say anything
about *how* you compile and link. But this works for all
compilers I've ever seen: Sun CC, g++, xlC, VC++...).
Generally, however, this is a bad idea, except for global
debugging versions of the operators.


Yes, I want to replace global new and delete.
How can I do this in Visual C++ 2005 Express Edition?
How can I link the code before the standard C++ library ?

Best Regards
/jerzy stachera
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top