views:

141

answers:

3

I came up with this as a quick solution to a debugging problem - I have the pointer variable and its type, I know it points to an array of objects allocated on the heap, but I don't know how many. So I wrote this function to look at the cookie that stores the number of bytes when memory is allocated on the heap.

template< typename T >
int num_allocated_items( T *p )
{
return *((int*)p-4)/sizeof(T);
}

//test
#include <iostream>
int main( int argc, char *argv[] )
{
    using std::cout; using std::endl;
    typedef long double testtype;
    testtype *p = new testtype[ 45 ];

    //prints 45
    std::cout<<"num allocated = "<<num_allocated_items<testtype>(p)<<std::endl;
    delete[] p;
    return 0;
}

I'd like to know just how portable this code is.

+11  A: 

It is not even remotely portable.

An implementation can perform heap bookkeeping however it wants and there is absolutely no way to portably get the size of a heap allocation unless you keep track of it yourself (which is what you should be doing).

James McNellis
As I suspected. Cheers.
carleeto
+2  A: 

Not portable. But why not use std::vector? Then you can ask it directly how many elements it contains, and you won't need to worry about memory management and exception safety.

jamesdlin
legacy code. That's why :)
carleeto
+1  A: 

You can globally overload new/delete operators on array, and put the size into the memory area. You get a portable solution.

The below code shows how:

void * operator new [] (size_t size)
{
    void* p = malloc(size+sizeof(int));
    *(int*)p = size;
    return (void*)((int*)p+1);
}

void operator delete [] (void * p)
{
    p = (void*)((int*)p-1);
    free(p);
}

template<typename T>
int get_array_size(T* p)
{
    return *((int*)p-1)/sizeof(T);
}


int main(int argc, char* argv[])
{
    int* a = new int[200];
    printf("size of a is %d.\n", get_array_size(a));
    delete[] a;
    return 0;
}

Result:

   size of a is 200.
Sherwood Hu
Was just wondering about that. Cheers.
carleeto
He said the array was allocated on the heap, not that it was allocated via `new[]`.
Dennis Zickefoose
@carleeto: To clarify my comment, since this seems to be something you're considering, in the general case you can't know how a pointer was allocated. Besides the possibility that the array was allocated via `malloc` directly, classes can override `operator new[]` on an individual basis. In which case, Sherwood's `get_array_size` is no more reliable than your own.
Dennis Zickefoose
@Dennis: Thanks for that. I was testing some code based on Sherwood's response and came across the same problem :)
carleeto