8

The following code I write must invoke both placement deallocation and allocation functions.

#include <iostream>
using namespace std;

struct A
{
    void * operator new [] (size_t t, int, int)
    {
        cout << "3 parameters allocation" << endl;
        return ::operator new[](t);
    }

    void operator delete [] (void *p, int, int)
    {
        cout << "3 parameters deallocation" << endl;
        return ::operator delete[](p);
    }
};

int main() 
{
    A *a = new (5,5) A[10]; //operator new [] (size_t, int, int) invoked
    delete [] a; //Error. Overload resolution is failed.
}

demo

5.3.4/22 says N3797:

A declaration of a placement deallocation function matches the declaration of a placement allocation function if it has the same number of parameters and, after parameter transformations (8.3.5), all parameter types except the first are identical. If the lookup finds a single matching deallocation function, that function will be called; otherwise, no deallocation function will be called.

It is not implement in C++11 or it is my misunderstanding?

  • 5
    I thought the placement deallocation function is only called when there's an exception during the construction of the object? [Live example](http://ideone.com/qcM8qj) – dyp Jul 29 '14 at 15:40
  • Related: http://stackoverflow.com/a/14119344 – dyp Jul 29 '14 at 15:42
  • @dyp Nice example! Thanks! I just don't know about restrictions cited by ecatmur and T.C. –  Jul 29 '14 at 17:27

3 Answers3

9

If a class-specific deallocation function is provided, a delete-expression that is not prefixed by the scope resolution operator is ill-formed unless a class-specific deallocation function with one or two parameters is available:

10 - If the type is complete and if deallocation function lookup finds both a usual deallocation function with only a pointer parameter and a usual deallocation function with both a pointer parameter and a size parameter, then the selected deallocation function shall be the one with two parameters. Otherwise, the selected deallocation function shall be the function with one parameter.

So you need to either:

  • provide void operator delete[](void*);,
  • provide void operator delete[](void*, size_t);, or
  • write ::delete[] a.
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 5
    §12.5 [class.free]/p4 is probably more relevant. "If the result of the lookup is ambiguous or inaccessible, or if the lookup selects a placement deallocation function, the program is ill-formed." – T.C. Jul 29 '14 at 16:15
1
A *a = new(5, 5) A[10]; 
A::operator delete[](a,5,5);

On Visual C++ 2013 this works great

Giobunny
  • 96
  • 2
1

If you want to have access to the original placement new parameters in your operator delete, you will have to store them in the allocated memory block and retrieve them later. For example (Live at Ideone):

struct A
{
    static void * operator new [] (size_t t, int first, int second);
    static void operator delete [] (void *p, size_t t);
    static void operator delete [] (void *p, int first, int second)
    {
        cout << "3 parameters deallocation: " << first << ", " << second << endl;
        return ::operator delete[](p);
    }
};

// simple POD struct to store the placement parameters
struct info {
    int first_param, second_param;
};

void* A::operator new [] (size_t t, int first, int second)
{
    cout << "3 parameters allocation: " << first << ", " << second << endl;
    // allocate sizeof(info) extra space to store the parameters
    auto const p = ::operator new[](t + sizeof(info));
    auto const pinfo = reinterpret_cast<char*>(p) + t;
    auto const tmp = info{first, second};
    std::copy_n(reinterpret_cast<const char*>(&tmp), sizeof(info), pinfo);
    return p;
}

static void A::operator delete [] (void *p, std::size_t t) {
    // retrieve the parameters that we stored in operator new [].
    auto const pinfo = reinterpret_cast<const char*>(p) + t;
    auto tmp = info{};
    std::copy_n(pinfo, sizeof(info), reinterpret_cast<char*>(&tmp));
    cout << "Deleting with original parameters: " << tmp.first_param << ", " << tmp.second_param << endl;
    ::operator delete[](p);
}
Casey
  • 41,449
  • 7
  • 95
  • 125