Re: implementations of new
On Apr 4, 5:58 am, "Ivan Novick" <ivan.d.nov...@gmail.com> wrote:
Hi,
I am wondering how "new" and "delete" are usually implemented.
Is it usually c++ code that is part of the standard library or do
compilers generate code for these directly?
Presumably its not mandated by the standard, but I am wondering about
typical implementations.
Thanks,
Ivan Novickhttp://www.0x4849.net
There are really two meanings to "new" and "delete." The first is the
new / delete "expression" which you can read about in 5.3 /5.4. The
second is the new /delete "allocation deallocation" functions, in
18.4 . It is the second form that you can actually override in your
program, and what you read about in Meyers Effective C++.
Expressions are always implemented by the compiler. The Allocation /
delallocation functions are in libraries.
To call the new expression without an allocation function, use
placement new:
void * f=getmemory(sizeof(T));
T* t = new (f) T;
There is no placement delete -- you have to do this manually:
t->~T();
releasememory(f);
Note that this is not as straightforward as is sounds in real life.
The flip side is to use the allocation functions directly:
void * f=::operator new(sizeof(T));
T* t = new (f) T;
t->~T();
::operator delete(f);
You might conclude that "regular" new/delete just combines these steps
steps together. But that is not what happens. My understanding of how
it is put together looks like this (in C++ pseudo code)
//MemFree helper class to handle
// exceptions
template<class T>
struct MemFree{
void * mem;
MemFree(void *_m=0):mem(_m) {}
~MemFree() {
if(overloaded_delete_operator<T>::value)
overloaded_delete_operator<T>::Scope::delete(mem);
else
::operator delete(mem);
}
void ignore() {mem=0;}
void reset(void*m) {mem=m;}
};
template<class T>
T* pseudo_new(args){
do{
MemFree del;
//use "alloction new" here
if(overloaded_new_operator<T>::value){
del.reset(
overloaded_new_operator<T>::Scope::operator new(sizeof(T));
}else{ //global new
del.reset(::operator new(sizeof(T));
}
if (del.mem) {
//use "expression new" here
//this could throw
T* ret= new (del.mem) T(args);
del.ignore(); //dont free on no throw
return ret
}
{
locker lk(my_mutex);//some synchronization object
//get user installed handler
void(*nh)()=set_new_handler(0);
//if not one then get out of here
if(!nh)throw std::bad_alloc;
set_new_handler(nh); //reset it back
}//release lock
(*nh)();// call it
}while(1);
}
template<class T>
void ::pseudo_delete(T*_p){
MostDerivedType * mdt=mostderived_cast<MostDerivedType>(_p);
mdt->~MostDerivedType();
if(overloaded_delete_operator<MostDerivedType>::value)
overloaded_delete_operator<MostDerivedType>::Scope::delete(_p);
else
// mdt is "leftmost" pointer
::operator delete(mdt);
}
The Array forms are more complicated, but basically uses a hidden
count of how many destructors must be called upon dallocation (NOTE :
NOT how many objects there are -- it could be that the ith out of n
objects upon construction throws, and only the first i have to be
destructed. Or, it could be an array of fundamental types, whereupon
most compilers leave the count out altogether).
I'm not sure if the above pseudo code is absolutly correct. It
certainly isn't valid C++, but the point I'm not clear on is if the
new_handler is invokded for overloaded operators new, or just the
global forms, and just where the locks are places in MT applications.
Lance
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]