Re: operator delete
Christoph Bartoschek wrote:
Alberto Ganesh Barbati wrote:
Christoph Bartoschek ha scritto:
Now I want to use a per object memory manager and define an appropriate
operator new:
void * operator new(std::size_t size, Mem & mem);
but now only
void operator delete(void * ptr, Mem & mem);
seems to match. Is there a way to get a matching operator delete that has
the size information? If this is not possible, why is the standard
inconsistent in this regard?
Those two operators match but in a sense that's completely different
from what you seem to expect. You should have searched the newsgroup
before asking, as this subject has been discussed very recently. Here's
the thread <http://tinyurl.com/vk6my>. As you will see there, things are
a bit more complicated than you may think.
Thanks for your response, but I've read the thread you mentioned and do not
think that it applies for my question. I do not want to have a placement
delete operator. The operator delete versions I mentioned are only called
if the constructor of the function throws an exception.
You can redefine the placement form of operator delete() in each
derived class, and simply get the sizeof() that class. This will work,
because the type of object is statically known at construction time,
when the exception could be thrown.
Another possible solution is to save the size for the duration of
placement new expression:
class Mem {
public:
void* allocate(size_t size);
void deallocate(void* p, size_t size);
};
class MemWithSize {
public:
MemWithSize(Mem& mem) : mem(mem) {} // implicit
operator Mem&() const { return mem; }
void* allocate(size_t n) {
return mem.allocate(saved_size = n);
}
void deallocate(void* p) {
mem.deallocate(p, saved_size);
}
private:
Mem& mem;
size_t saved_size;
};
class A {
public:
void* operator new(size_t size, MemWithSize mws) {
return mws.allocate(size);
}
void operator delete(void* p, MemWithSize mws) {
mws.deallocate(p);
}
};
Mem mem;
A* p = new (mem) A();
But I see that the standard has one specific case where the size of the
object that has to be deleted is passed to the operator delete and I ask
myself why is this not possible for other operator delete versions. And why
is it not possible to get the size of an object in the same way the
compiler passes it to the specific operator delete.
The size information is not stored with the object, but provided by the
destructor of that object. Let us have:
struct A {
virtual ~A() { destroy(); }
destroy() { /* ... */ }
void operator delete(void* p, size_t size) { /* ... */ }
};
See how the destructor is implemented by the compiler:
struct A {
~A(bool deleting)
{
destroy();
if (deleting) {
operator delete(this, sizeof(A));
}
}
destroy() { /* ... */ }
void operator delete(void* p, size_t size) { /* ... */ }
};
Hence the standard defines the rules:
1. the size is correct if the destructor is virtual, and
2. operator delete() is found in the scope of destructor.
The parameter "deleting" is true when the object is deleted thru
non-placement operator delete:
A* p = new A();
delete p; // actually: p->~A(true);
A a;
a.~A(); // actually: a.~A(false);
Thus you cannot determine the size of the object until you destroy it
using the delete-expression.
To emulate a polymorphic deletion with custom allocator, we'll need a
virtual function that deletes:
class A {
public:
void* operator new(size_t size, Mem& mem) {
return mem.allocate(size);
}
virtual void delete_it(Mem& mem) {
this->~A();
mem.deallocate(this, sizeof(A));
}
};
Mem mem;
A* p = new (mem) A();
p->delete_it(mem);
In each case, the size is determined statically as sizeof(A).
--
Andrei Polushin
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]