Search code examples
c++operator-overloadingreallocdelete-operator

overload delete[] operator to allow shrinkable arrays of types with destructor


We're trying to overload the delete[] operator to achieve shrinkable oriented to objects arrays.

It works fine with data types without specific destructor.

When the data type has a specified destructor, the new[] operator needs extra bytes.

Could you help us please to answer these questions?

  1. Why does the new[] operator require extra bytes for data types with specific destructor?
  2. Will always the new[] operator request these bytes or is it library dependent?
  3. Is it possible to know if the data type has a specific destructor with an if statement?

The code should throw an unhandled exception when it tries to shrink the array of B's.

#include<cstdlib>
#include<iostream>
using namespace std;

void*operator new[](size_t s){
    cout<<"Block size: "<<s<<endl;
    return malloc(s);
}
void operator delete[](void*p){
    free(p);
}
void operator delete[](void*p,size_t s){
    //Is it possible to know if the data type has a specific destructor?
    bool destructor=0;
    if(destructor){
        p=(char*)p-8,s+=8;
    }
    cout<<"New block size: "<<s<<endl;
    if(realloc(p,s)!=p)throw 0;
}

struct A{
    char a;

    A():a(0){}
    ~A()=default;
};

struct B{
    char b;

    B():b(0){}
    ~B(){}
};

int main(){
    unsigned S=10,s=4;
    cout<<"Creating "<<S<<" A's"<<endl;
    A*a=new A[S];
    cout<<"Creating "<<S<<" B's"<<endl;
    B*b=new B[S];
    cout<<"Shrinking A to "<<s<<" elements"<<endl;
    operator delete[](a,sizeof(A)*s);
    cout<<"Shrinking B to "<<s<<" elements"<<endl;
    operator delete[](b,sizeof(B)*s);
    cout<<"Deleting A and B"<<endl;
    delete[]b,delete[]a;
    return 0;
}

Related answered question:

overload delete[] operator with specific arguments


Solution

  • This may answer points 1 and 2

    When operator new is used to create a new array, a cookie is usually stored to remember the allocated length (number of array elements) so that it can be deallocated correctly.

    Specifically:

    No cookie is required if the array element `type T` has a trivial destructor.
    

    That means:

    • Because struct A has a trivial destructor it doesn't require a cookie.
    • Because struct B has a specific destructor it requires a cookie of sizeof(size_t) bytes, which is stored inmediatly at the left of the array.

    Reference: Itanium C++ ABI