"Dmitriy V'jukov" <dvyukov@[EMAIL PROTECTED]
> wrote in message
news:4eee5b3c-df5a-4b28-af4e-863ddaecf149@[EMAIL PROTECTED]
Oct 3, 3:56 pm, Michel Decima <michel.dec...@[EMAIL PROTECTED]
> wrote:
> > > derived2* d2 = new derived2 (); // CRASH! Allocate memory only for
> > > derived1, derived2 will not fit into that memory
> >
> > But if you use the 'sz' parameter of operator new to call malloc(),
> > then you will allocate enough memory for derived2.
> > And you can overload the class-local delete operator with a second
> > size_t parameter, you will known the size of the object to deallocate:
> Cool! I completely miss this moment.
> The point is that if user calls delete for object and object doesn't
> have virtual destructor, then static and dynamic types of object MUST
> be identical. So compiler can always determine correct size.
Also, I don't think that your `object_t' class needs to be a template at
all. Here is test code:
_________________________________________________________________
#include <cstdio>
#include <cstdlib>
#include <new>
struct custom_allocator {
static void* allocate(std::size_t size)
throw(std::bad_alloc) {
void* const mem = std::malloc(size);
if (! mem) {
throw std::bad_alloc();
}
std::printf("custom_allocator::allocate(%p, %lu)\n",
(void*)mem, (unsigned long)size);
return mem;
}
static void deallocate(void* const mem, std::size_t size)
throw() {
if (mem) {
std::printf("custom_allocator::deallocate(%p, %lu)\n",
(void*)mem, (unsigned long)size);
std::free(mem);
}
}
};
struct allocator_base {
void* operator new(std::size_t size)
throw(std::bad_alloc) {
return custom_allocator::allocate(size);
}
void* operator new [](std::size_t size)
throw(std::bad_alloc) {
return custom_allocator::allocate(size);
}
void operator delete(void* mem, std::size_t size)
throw() {
custom_allocator::deallocate(mem, size);
}
void operator delete [](void* mem, std::size_t size)
throw() {
custom_allocator::deallocate(mem, size);
}
};
template<std::size_t T_size>
class buf : public allocator_base {
char mem[T_size];
public:
virtual ~buf() throw() {}
};
class buf2 : public buf<1234> {
char mem2[1000];
};
int main() {
buf<1024>* b1 = new buf<1024>;
delete b1;
buf2* b2 = new buf2;
delete b2;
b2 = new buf2[5];
delete [] b2;
return 0;
}
_________________________________________________________________
On every version of GCC I have, I get the following output on a 32-bit
machine:
custom_allocator::allocate(00246C50, 1028)
custom_allocator::deallocate(00246C50, 1028)
custom_allocator::allocate(002472A8, 2240)
custom_allocator::deallocate(002472A8, 2240)
custom_allocator::allocate(002472A8, 11204)
custom_allocator::deallocate(002472A8, 11204)
On every version of MSVC, I get:
custom_allocator::allocate(00365B28, 1028)
custom_allocator::deallocate(00365B28, 1028)
custom_allocator::allocate(00362850, 2240)
custom_allocator::deallocate(00362850, 2240)
custom_allocator::allocate(00366FA8, 11204)
custom_allocator::deallocate(00366FA8, 2240)
Well, AFFLICT, MSVC has a NASTY bug indeed! That too bad. There is nothing
worse that a bug in the ****%ing compiler! Ouch.
[...]
> The only thing I don't like is dynamic dispatch on size.
> Allocation/deallocation functions in fixed size allocator can be as
> small as 5 machine instructions. So dynamic dispatch on size can
> increase cost of allocation several times!
> The only thing we can do is:
> __forceinline static void* operator new ( size_t sz )
> {
> // resolution at runtime
> if ( sz <= 4 && sizeof(derived_t) <= 4 )
> return alloc_4() ;
> else if ( sz <= 8 && sizeof(derived_t) <= 8 )
> return alloc_8() ;
> else if ( sz <= 16 && sizeof(derived_t) <= 16 )
> return alloc_16() ;
> else
> return ::malloc( sz ) ;
> }
>
> and pray for inlining :)
lol. ;^D


|