Sure, for some definition of "usable". Overhead such as block
size, freelist pointer etc., are obviously outside of the
returned block. But the array size that's specified in a call to
new [], and the vptr, are definitely inside the malloc'ed block,
and may be before the struct data.
Hmm. Last I was working with it, the array size to new[] was outside
the block, just as the block size to malloc(). The vptr is part of any
struct/class with virtual functions, and effectively acts as a hidden
class member, so you get one of those inside the block, and it's
included in sizeof.
//Allocated Space: The Final Frontier!
#include <stdio.h> //cout sucks
class Foo
{
int x;
int y;
int z;
};
class Bar
{
int x;
int y;
int z;
virtual int get_x() {return x;}
};
int main()
{
printf("sizeof(int) = %u\n",sizeof(int));
printf("sizeof(int*) = %u\n",sizeof(int*));
printf("sizeof(Foo) = %u\n",sizeof(Foo));
printf("sizeof(Bar) = %u\n",sizeof(Bar));
Foo *foo = new Foo[10];
printf("foo = %p/%p = %u\n",foo,foo+10,(char *)(foo+10)-(char *)foo);
Bar *bar = new Bar[10];
printf("bar = %p/%p = %u\n",bar,bar+10,(char *)(bar+10)-(char *)bar);
return 0;
}
rosuav@sikorsky:~$ g++ frontier.cpp && ./a.out
sizeof(int) = 4
sizeof(int*) = 8
sizeof(Foo) = 12
sizeof(Bar) = 24
foo = 0xf38010/0xf38088 = 120
bar = 0xf38090/0xf38180 = 240
The rules of structs are that they be contiguous, that they be laid
out sequentially, and that any padding needed between structures is at
the end of the previous one (which is why three of 4 bytes makes 12
bytes, but three of 4 bytes plus 8 bytes makes 24 - the eight-byte
pointer has to be aligned on a multiple of eight bytes, so having a
20-byte structure that starts with an 8-byte pointer is a no-no). The
allocated block of memory is, by definition, the same as the pointer
to its first element. As it happens, the pointer bar is not synonymous
with &bar->x, &bar->y, or &bar->z, which means the vptr is at the
beginning of bar, which makes sense; but the compiler's not obliged to
do that, and in some cases may choose not to - for instance, if bar
(with a virtual function) inherited from foo (with none), it might be
convenient to allow a pointer-cast to not change the value of the
pointer. (g++ 4.7.2 still puts the vptr at the beginning of bar in
that case, but other compilers or other versions may differ.)
Array size is outside the block, presumably before it, as &foo[0] is
by definition identical to foo, and there's no room inside the
structure for any spare data. Virtual function table is inside the
block because it's a hidden member of the object (like __class__ in
Python, only better hidden).