operator new, delete, static variable lifecyle and more

J

Jonan

Hello,

For several reasons I want to replace the built-in memory management with
some custom built. The mem management itlsef is not subject to my question -
it's ok to the point that I have nice and working allocation deallocation
routines. However, I don't want to loose the nice extras of new operator,
like - constructor calling, typecasting the result, keeping the array size,
etc.
For another bunch of reasons, outside this scope I want the memory
management to be global, and not per-class.
So it seemed pretty obvious to me that I could overload the global new
operator and do the work. And here start the series of problems with
mutually exclusive solutions:

- When I try to use STL they all refer to my new and delete operators. This
by itself is not bad, BUT. My memory manager (so to say) is static variable
(singleton based implemetantion) and so it has some lifecyle. Unfortunetely
some static variable in STL - like 'locale'-s managent have longer life and
at some points of program finish it refers to some memory that my manager
has already freed. Since I cannot make my object to live longer than STL's -
this leaded to different approach:
- I tried to overload the new operator in an unique way - i.e. with some
useless parameter to prevent STL from using it. so far so good. But
overloading delete operator in such a manner is not possible, since it does
not accept additional parameters. So I came up with solution in which for
allocation I use my custom made new operator and for deallocation - a
function call. With macroses it could look nice. But here comes the next
problem.
- Except deallocation delete operator calls destructors. This, by itself is
not a problem, BUT. For example on VC7 compiler the new[] operator allocated
sizeof(size_t) bytes more at the beginning to put the array size there and
__returns the pointer AFTER those sizeof(size_t) bytes__. Even that is not
SO bad. But when we add two more facts - (1) when the type allocated has no
destructor the new operator does NOT allocate that extra storage, (2) none
of the above stays in the C++ standard. So implementing delete[] on you own
involves knowledge whether passed type has destructor or not. And again -
this is pretty compiler specific solution if there is any at all.

Please, if anybody sees some mistake or misjudgement in my observation or
has an idea how I can workaround this and make it possible to use new and
delete without rewriting tons of automatic code - give my an advice.
Thank you in advance,
-Jonan
 
J

John Harrison

Jonan said:
Hello,

For several reasons I want to replace the built-in memory management with
some custom built. The mem management itlsef is not subject to my question -
it's ok to the point that I have nice and working allocation deallocation
routines. However, I don't want to loose the nice extras of new operator,
like - constructor calling, typecasting the result, keeping the array size,
etc.
For another bunch of reasons, outside this scope I want the memory
management to be global, and not per-class.
So it seemed pretty obvious to me that I could overload the global new
operator and do the work. And here start the series of problems with
mutually exclusive solutions:

- When I try to use STL they all refer to my new and delete operators. This
by itself is not bad, BUT. My memory manager (so to say) is static variable
(singleton based implemetantion) and so it has some lifecyle. Unfortunetely
some static variable in STL - like 'locale'-s managent have longer life and
at some points of program finish it refers to some memory that my manager
has already freed. Since I cannot make my object to live longer than STL's -
this leaded to different approach:

Write your allocator without constructor or destructor. You can rely on
zero-initialisation to put the allocator into a predictable state on program
startup and hopefully you can rely on your OS to reclaim any resources on
program exit.

john
 
T

Tom Widmer

Hello,

For several reasons I want to replace the built-in memory management with
some custom built. The mem management itlsef is not subject to my question -
it's ok to the point that I have nice and working allocation deallocation
routines. However, I don't want to loose the nice extras of new operator,
like - constructor calling, typecasting the result, keeping the array size,
etc.
For another bunch of reasons, outside this scope I want the memory
management to be global, and not per-class.
So it seemed pretty obvious to me that I could overload the global new
operator and do the work. And here start the series of problems with
mutually exclusive solutions:

- When I try to use STL they all refer to my new and delete operators. This
by itself is not bad, BUT. My memory manager (so to say) is static variable
(singleton based implemetantion) and so it has some lifecyle. Unfortunetely
some static variable in STL - like 'locale'-s managent have longer life and
at some points of program finish it refers to some memory that my manager
has already freed. Since I cannot make my object to live longer than STL's -

There are a few strategies you can use to get around this problem. For
a start, you don't have to deallocate memory at all at program exit,
but instead can generally rely on the OS to do it for you. On some
platforms I imagine there are #pragmas that you can use to ensure that
your object gets created before the locale stuff.
this leaded to different approach:
- I tried to overload the new operator in an unique way - i.e. with some
useless parameter to prevent STL from using it. so far so good. But
overloading delete operator in such a manner is not possible, since it does
not accept additional parameters. So I came up with solution in which for
allocation I use my custom made new operator and for deallocation - a
function call. With macroses it could look nice. But here comes the next
problem.
- Except deallocation delete operator calls destructors. This, by itself is
not a problem, BUT. For example on VC7 compiler the new[] operator

I think you mean a new[] expression - the difference is important. new
Foo[x] doesn't directly call operator new[]. e.g. on some compilers,
new[] will call ::eek:perator new[](sizeof(Foo) * x + 4) and will return
the value offset by 4.

allocated
sizeof(size_t) bytes more at the beginning to put the array size there and
__returns the pointer AFTER those sizeof(size_t) bytes__. Even that is not
SO bad. But when we add two more facts - (1) when the type allocated has no
destructor the new operator does NOT allocate that extra storage, (2) none
of the above stays in the C++ standard. So implementing delete[] on you own
involves knowledge whether passed type has destructor or not. And again -
this is pretty compiler specific solution if there is any at all.

Why do you think you need to know how delete[] and new[] expressions
are implemented? You just need to overload operator new, operator
new[], operator delete and operator delete[]. The new[] expressions
will automatically ask operator new for more storage and do any
pointer adjustments for you. Same for delete[] - operator delete[]
will be passed the actual start of the memory block, not a 4 byte
offset into it, regardless of whether the type has a user defined
destructor or not.

In fact, ::eek:perator delete[] has no access to the type of the object
being deleted in any case, so how were you going to check whether it
had an non-trivial destructor or not?
Please, if anybody sees some mistake or misjudgement in my observation or
has an idea how I can workaround this and make it possible to use new and
delete without rewriting tons of automatic code - give my an advice.

I don't actually see the problem at the moment - could you explain
further?

Tom
 
J

Jonan

Yes, I thought about leaving my allocator undestructed - in this way citing
of "my" memory want cause errors. But since I want that allocator to be
reasonable self-maintaining unit it's not acceptable for me to leave OS do
the dealloctions.
And, in case, I was mis-understood the problem with ctors and dtors is not
with allocators' ones. It is because:

T* p = new T [mySize];

besides allocation (which I'm glad to do! :) it calls mySize ctors of type
T. And this:

delete[] p;

calls mySize destructors before deallocating.
But the behavior of new[] and delete[] depends on the fact, whether T has
destructor or not, so if I override 'operator new' I have to know this fact
in 'delete' too, etc., etc.

I want to implement only the allocation/deallocation itlsef not all of the
work.
-Jonan
 
J

Jonan

Hi,
I don't actually see the problem at the moment - could you explain
further?

Tom

Sure! But first to answer some of you comments/questions.
There are a few strategies you can use to get around this problem. For
a start, you don't have to deallocate memory at all at program exit,
but instead can generally rely on the OS to do it for you. On some
platforms I imagine there are #pragmas that you can use to ensure that
your object gets created before the locale stuff.

- for #pargma tricks and ensuring some more "minutes" life for my object.
Yes - they are, but I I neither know, nor like such tricks and - I want this
to be more portable and more consistent. For suggestion to leave OS do it -
I know about this, I want the allocator to be quite separate unit, so it's
not a good option. I'm seeking some other solution.
I think you mean a new[] expression - the difference is important. new
Foo[x] doesn't directly call operator new[]. e.g. on some compilers,
new[] will call ::eek:perator new[](sizeof(Foo) * x + 4) and will return
the value offset by 4.

- for operator new[] - this's exactly what I mean. sorry for 'mixing new[]'
expression with 'new[] operator'. But it adds those 4 bytes only if the
class has destructor defined (i.e. non-trivial) - at least VC7 is behaving
like this. it referes to next:
In fact, ::eek:perator delete[] has no access to the type of the object
being deleted in any case, so how were you going to check whether it
had an non-trivial destructor or not?
- for operator delete[] - delete doesn't know by itself for the type by it
decides based on the type passed to it. What do I mean? Given this:

delete[] (T*)p;

if T doesnt have destructor it'll not "walk back" 4 bytes and will not
attempt to call destructors; If it does - it will rely on the fact that 4
bytes before p there is number of elements and will attempt to call this
number of ~T() starting from p. (sorry if I'm too specific). Given that I
can simulate same behaviour like this:

template<typename T>
void _my_delete(T* p);

So I'll use T do decide for destruction if I can...
Why do you think you need to know how delete[] and new[] expressions
are implemented? You just need to overload operator new, operator
new[], operator delete and operator delete[]. The new[] expressions
will automatically ask operator new for more storage and do any
pointer adjustments for you. Same for delete[] - operator delete[]
will be passed the actual start of the memory block, not a 4 byte
offset into it, regardless of whether the type has a user defined
destructor or not.
- just overloading. Hmmm.. As I said - this was my first attempt but it gets
wrong while using STL. I agree that leaving destruction for OS IS some
solution but I'm seeking for another one.

I hope this clears my problems.
Thanks,
-Jonan
 
J

John Harrison

Jonan said:
Yes, I thought about leaving my allocator undestructed - in this way citing
of "my" memory want cause errors. But since I want that allocator to be
reasonable self-maintaining unit it's not acceptable for me to leave OS do
the dealloctions.
And, in case, I was mis-understood the problem with ctors and dtors is not
with allocators' ones. It is because:

T* p = new T [mySize];

besides allocation (which I'm glad to do! :) it calls mySize ctors of type
T. And this:

delete[] p;

calls mySize destructors before deallocating.
But the behavior of new[] and delete[] depends on the fact, whether T has
destructor or not, so if I override 'operator new' I have to know this fact
in 'delete' too, etc., etc.

I want to implement only the allocation/deallocation itlsef not all of the
work.

That is all you have to do. You are mixing up the new operator with operator
new.

T* p = new T [mySize];

This calls the new operator. The new operator calls operator new to allocate
some memory and then calls the constructors. You overload the operator new
part to allocate some memory but the constructors will still be called by
the new operator.

Same for delete.

So all you have to do when overloading operator new is allocate some memory.
Constructors will still be called in the usual way.

john
 
J

Jonan

It's seems that I've missed that big point, since several people asked me
for that.
I __know__ that overloading operator new() won't prevent compiler for
calling ctors and dtors (for operator delete) respectively.
The problem is that if I override operator new() and operator delete() they
get called for some STL objects that live longer than my allocator and this
causes general fault.
SO, one option is to leave operator new and delete for
debug-only-redefinition and switch to regular function - the profit is that
nobody, except me will call them. The loss is excatly what I said: nobody
will do ctor calling for me.
So this is the question at all - HOW to make use of operator new and delete,
without (1) leaving OS to cleanup my stuff, (2) permitting some static
objects to call destructed objects (in my case - use freed memory).
Hope this makes it more clear.
-Jonan

John Harrison said:
Jonan said:
Yes, I thought about leaving my allocator undestructed - in this way citing
of "my" memory want cause errors. But since I want that allocator to be
reasonable self-maintaining unit it's not acceptable for me to leave OS do
the dealloctions.
And, in case, I was mis-understood the problem with ctors and dtors is not
with allocators' ones. It is because:

T* p = new T [mySize];

besides allocation (which I'm glad to do! :) it calls mySize ctors of type
T. And this:

delete[] p;

calls mySize destructors before deallocating.
But the behavior of new[] and delete[] depends on the fact, whether T has
destructor or not, so if I override 'operator new' I have to know this fact
in 'delete' too, etc., etc.

I want to implement only the allocation/deallocation itlsef not all of the
work.

That is all you have to do. You are mixing up the new operator with operator
new.

T* p = new T [mySize];

This calls the new operator. The new operator calls operator new to allocate
some memory and then calls the constructors. You overload the operator new
part to allocate some memory but the constructors will still be called by
the new operator.

Same for delete.

So all you have to do when overloading operator new is allocate some memory.
Constructors will still be called in the usual way.

john
 
J

John Harrison

Jonan said:
It's seems that I've missed that big point, since several people asked me
for that.
I __know__ that overloading operator new() won't prevent compiler for
calling ctors and dtors (for operator delete) respectively.
The problem is that if I override operator new() and operator delete() they
get called for some STL objects that live longer than my allocator and this
causes general fault.
SO, one option is to leave operator new and delete for
debug-only-redefinition and switch to regular function - the profit is that
nobody, except me will call them. The loss is excatly what I said: nobody
will do ctor calling for me.
So this is the question at all - HOW to make use of operator new and delete,
without (1) leaving OS to cleanup my stuff, (2) permitting some static
objects to call destructed objects (in my case - use freed memory).
Hope this makes it more clear.
-Jonan

I don't think there is any portable way to force your allocator to be
constructed first (and destructed last). But there sometimes are compiler
specific methods, perhaps you should look into this.

John
 
T

Tom Widmer

- for #pargma tricks and ensuring some more "minutes" life for my object.
Yes - they are, but I I neither know, nor like such tricks and - I want this
to be more portable and more consistent. For suggestion to leave OS do it -
I know about this, I want the allocator to be quite separate unit, so it's
not a good option. I'm seeking some other solution.

Well, one way is to use the header trick, where every TU that wants to
use your allocator must #include is *before* any other headers. Then
it declares a global object of a type whose constructor initialises
your library (and registers it for destruction with std::atexit) -
obviously only the first such object created will actual do any
creation. e.g.

//in your header somewhere
namespace
{
allocator_init init; //define global object
}

Now, every source file that includes your header will attempt to
initialise the allocator, and it will do so before any other globals
it declares, so that your allocator is guaranteed to be initialized
before any other objects that might use it.

The only problem with this is that some C++RT libraries do use the
#pragma tricks, and there's no way to get your initialisation done
before them without using #pragma tricks yourself.
I think you mean a new[] expression - the difference is important. new
Foo[x] doesn't directly call operator new[]. e.g. on some compilers,
new[] will call ::eek:perator new[](sizeof(Foo) * x + 4) and will return
the value offset by 4.
- for operator new[] - this's exactly what I mean. sorry for 'mixing new[]'
expression with 'new[] operator'. But it adds those 4 bytes only if the
class has destructor defined (i.e. non-trivial) - at least VC7 is behaving
like this. it referes to next:
In fact, ::eek:perator delete[] has no access to the type of the object
being deleted in any case, so how were you going to check whether it
had an non-trivial destructor or not?
- for operator delete[] - delete doesn't know by itself for the type by it
decides based on the type passed to it. What do I mean? Given this:

delete[] (T*)p;

if T doesnt have destructor it'll not "walk back" 4 bytes and will not
attempt to call destructors; If it does - it will rely on the fact that 4
bytes before p there is number of elements and will attempt to call this
number of ~T() starting from p. (sorry if I'm too specific). Given that I
can simulate same behaviour like this:

template<typename T>
void _my_delete(T* p);

So I'll use T do decide for destruction if I can...

Ahh, I was missing the point, that your custom _my_delete function
needs to know how new[] expressions work in order to know how to
deallocate the memory and destroy the objects.

Actually, the problem is even worse than you thought. Your _my_delete
will have no idea what the base address of the object passed in. e.g.

struct Foo
{
virtual ~Foo(){}
int i;
};

struct Bar: public virtual Foo
{
int j;
};

#include <iostream>

int main()
{
Bar b;
Foo* f = &b;
std::cout << static_cast<void*>(f) << '\n';
std::cout << dynamic_cast<void*>(f) << '\n';
}

The dynamic_cast gives the true base address of the object.

So, your delete replacement has to:
call the destructor
work out whether the object is polymorphic
Yes: work out the real base address of the object using dynamic_cast
No: static_cast to void*
deallocate the memory using the address

Your delete[] replacement has to:
work out whether the objects have non-trivial destructors (or similar)
call the destructors and adjust the pointer if necessary
deallocate the memory

Hmm, too much of that is non-portable to be attractive. Another
possible solution:

void* operator new(size_t size)
{
if (allocator::is_initialised())
//use allocator
else
//use malloc
}

void operator delete(void* address)
{
if (allocator::is_initialised())
//deallocate using allocator
else
//use free
}

Worth a try at least, since anything created before your allocator is
likely to be destroyed after it. Another thing to try would be to tag
allocated memory in such a way that you can detect at runtime whether
your allocator was used for the allocation or not.

The final solution is to stop using new expressions too! So as well as
_my_delete you have a _my_new (and some macro magic). Maybe something
like this:

#define NEW(T, args) (new (alloc(sizeof(T)), alloctag) T args)

You'll need to override the equivalent operator delete to deal with
deallocation in the face of exceptions. Usage would be:

Foo* f = NEW(Foo, (10, 12));

which isn't very nice. With proper argument forwarding (in a future
C++) it could be improved to a non-macro NEW(Foo)(10, 12);

Also you could read this: http://www.scs.cs.nyu.edu/~dm/c++-new.html.
I don't agree with all of it, but it seems clear that overloading of
operator new is pretty broken unless done in a simple way.

Tom
 
J

Jonan

Thank you a lot for detailed look. Unfortunetely most of the possible
solutions passed thru my mind before stepping here to ask for help and as
you note for most - they are hardly solution to the problem, and more a
workaround.
Probably some more general way is to do my best and make my allocator object
defined first. I'm not sure whether some additional libraries will be the
problem, since they - most probably will use their own operator new and
delete? I'm not sure. In each case - this solution is rated last on my list.

I haven't think about the dynamic_cast, static_cast overhead for possible
custom implementation of _delete_ but isn't that just in case I use operator
new for allocation and my custom delete for deallocation?

The is_initialized() was something that almost tried, but than I realized
the that will not guarantee me much - imagine that an object which is
defined before my allocator and which constructor is called very early, but
which leaves the deallocation for the destructor - i.e. allocates necessary
memory "on demand". If between initialization of other object and my
somebody allocated memory using my allocator - the problem on "early object"
will appear. So this could work for some cases, but it's not a general
solution.

I think that I'll leave new and delete and will work on my custom functions
for that, although the link you sent me mentions some problems with macroses
when types templated. Generally no macros is needed, since it can be
template function like:

template<typename T>
T* allocate(size_t sz);

but for debugging purposes it'll be necessary to be wrapped with macros to
be able to define that macros with __FILE__, etc. vars.
I'll see what will go out of this.
-Jonan


Tom Widmer said:
- for #pargma tricks and ensuring some more "minutes" life for my object.
Yes - they are, but I I neither know, nor like such tricks and - I want this
to be more portable and more consistent. For suggestion to leave OS do it -
I know about this, I want the allocator to be quite separate unit, so it's
not a good option. I'm seeking some other solution.

Well, one way is to use the header trick, where every TU that wants to
use your allocator must #include is *before* any other headers. Then
it declares a global object of a type whose constructor initialises
your library (and registers it for destruction with std::atexit) -
obviously only the first such object created will actual do any
creation. e.g.

//in your header somewhere
namespace
{
allocator_init init; //define global object
}

Now, every source file that includes your header will attempt to
initialise the allocator, and it will do so before any other globals
it declares, so that your allocator is guaranteed to be initialized
before any other objects that might use it.

The only problem with this is that some C++RT libraries do use the
#pragma tricks, and there's no way to get your initialisation done
before them without using #pragma tricks yourself.
I think you mean a new[] expression - the difference is important. new
Foo[x] doesn't directly call operator new[]. e.g. on some compilers,
new[] will call ::eek:perator new[](sizeof(Foo) * x + 4) and will return
the value offset by 4.
- for operator new[] - this's exactly what I mean. sorry for 'mixing new[]'
expression with 'new[] operator'. But it adds those 4 bytes only if the
class has destructor defined (i.e. non-trivial) - at least VC7 is behaving
like this. it referes to next:
In fact, ::eek:perator delete[] has no access to the type of the object
being deleted in any case, so how were you going to check whether it
had an non-trivial destructor or not?
- for operator delete[] - delete doesn't know by itself for the type by it
decides based on the type passed to it. What do I mean? Given this:

delete[] (T*)p;

if T doesnt have destructor it'll not "walk back" 4 bytes and will not
attempt to call destructors; If it does - it will rely on the fact that 4
bytes before p there is number of elements and will attempt to call this
number of ~T() starting from p. (sorry if I'm too specific). Given that I
can simulate same behaviour like this:

template<typename T>
void _my_delete(T* p);

So I'll use T do decide for destruction if I can...

Ahh, I was missing the point, that your custom _my_delete function
needs to know how new[] expressions work in order to know how to
deallocate the memory and destroy the objects.

Actually, the problem is even worse than you thought. Your _my_delete
will have no idea what the base address of the object passed in. e.g.

struct Foo
{
virtual ~Foo(){}
int i;
};

struct Bar: public virtual Foo
{
int j;
};

#include <iostream>

int main()
{
Bar b;
Foo* f = &b;
std::cout << static_cast<void*>(f) << '\n';
std::cout << dynamic_cast<void*>(f) << '\n';
}

The dynamic_cast gives the true base address of the object.

So, your delete replacement has to:
call the destructor
work out whether the object is polymorphic
Yes: work out the real base address of the object using dynamic_cast
No: static_cast to void*
deallocate the memory using the address

Your delete[] replacement has to:
work out whether the objects have non-trivial destructors (or similar)
call the destructors and adjust the pointer if necessary
deallocate the memory

Hmm, too much of that is non-portable to be attractive. Another
possible solution:

void* operator new(size_t size)
{
if (allocator::is_initialised())
//use allocator
else
//use malloc
}

void operator delete(void* address)
{
if (allocator::is_initialised())
//deallocate using allocator
else
//use free
}

Worth a try at least, since anything created before your allocator is
likely to be destroyed after it. Another thing to try would be to tag
allocated memory in such a way that you can detect at runtime whether
your allocator was used for the allocation or not.

The final solution is to stop using new expressions too! So as well as
_my_delete you have a _my_new (and some macro magic). Maybe something
like this:

#define NEW(T, args) (new (alloc(sizeof(T)), alloctag) T args)

You'll need to override the equivalent operator delete to deal with
deallocation in the face of exceptions. Usage would be:

Foo* f = NEW(Foo, (10, 12));

which isn't very nice. With proper argument forwarding (in a future
C++) it could be improved to a non-macro NEW(Foo)(10, 12);

Also you could read this: http://www.scs.cs.nyu.edu/~dm/c++-new.html.
I don't agree with all of it, but it seems clear that overloading of
operator new is pretty broken unless done in a simple way.

Tom
 
J

Jonan

Hi!

I finally found the solution to the problem and I just wonder how I didn't
figure it out earlier - reference counting. I realized that this problem is
not the same as standard singleton problem, because here I have two mirrored
operations - allocation and deallocation: allocation increases the operation
counter (more accurate than "reference") and deallocation decreases it. When
will the deallocation happens?
The destructor of the allocator "marks" that it is called without free
anything. The deallocation routines checks each time wether the two
conditions are satisfied - operation counter is zero and allocator is marked
for destruction. Only than it is destructed.
Acutlly even w/o that flagging it'll work but than it might slow down the
program, because every time operation counter reached zero it'll destroy the
memory pool and the next allocation call have to recontruct it.
-Jonan



Jonan said:
Hello,

For several reasons I want to replace the built-in memory management with
some custom built. The mem management itlsef is not subject to my question -
it's ok to the point that I have nice and working allocation deallocation
routines. However, I don't want to loose the nice extras of new operator,
like - constructor calling, typecasting the result, keeping the array size,
etc.
For another bunch of reasons, outside this scope I want the memory
management to be global, and not per-class.
So it seemed pretty obvious to me that I could overload the global new
operator and do the work. And here start the series of problems with
mutually exclusive solutions:

- When I try to use STL they all refer to my new and delete operators. This
by itself is not bad, BUT. My memory manager (so to say) is static variable
(singleton based implemetantion) and so it has some lifecyle. Unfortunetely
some static variable in STL - like 'locale'-s managent have longer life and
at some points of program finish it refers to some memory that my manager
has already freed. Since I cannot make my object to live longer than STL's -
this leaded to different approach:
- I tried to overload the new operator in an unique way - i.e. with some
useless parameter to prevent STL from using it. so far so good. But
overloading delete operator in such a manner is not possible, since it does
not accept additional parameters. So I came up with solution in which for
allocation I use my custom made new operator and for deallocation - a
function call. With macroses it could look nice. But here comes the next
problem.
- Except deallocation delete operator calls destructors. This, by itself is
not a problem, BUT. For example on VC7 compiler the new[] operator allocated
sizeof(size_t) bytes more at the beginning to put the array size there and
__returns the pointer AFTER those sizeof(size_t) bytes__. Even that is not
SO bad. But when we add two more facts - (1) when the type allocated has no
destructor the new operator does NOT allocate that extra storage, (2) none
of the above stays in the C++ standard. So implementing delete[] on you own
involves knowledge whether passed type has destructor or not. And again -
this is pretty compiler specific solution if there is any at all.

Please, if anybody sees some mistake or misjudgement in my observation or
has an idea how I can workaround this and make it possible to use new and
delete without rewriting tons of automatic code - give my an advice.
Thank you in advance,
-Jonan
 
T

Tom Widmer

Hi!

I finally found the solution to the problem and I just wonder how I didn't
figure it out earlier - reference counting. I realized that this problem is
not the same as standard singleton problem, because here I have two mirrored
operations - allocation and deallocation: allocation increases the operation
counter (more accurate than "reference") and deallocation decreases it. When
will the deallocation happens?
The destructor of the allocator "marks" that it is called without free
anything. The deallocation routines checks each time wether the two
conditions are satisfied - operation counter is zero and allocator is marked
for destruction. Only than it is destructed.
Acutlly even w/o that flagging it'll work but than it might slow down the
program, because every time operation counter reached zero it'll destroy the
memory pool and the next allocation call have to recontruct it.

Doesn't this have a problem if some memory is allocated before your
allocator is created, but destroyed before it is destroyed? This might
be a problem, e.g. for locale facet tables, that might be created
before your allocator but then resized later.

Tom
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top