перегрузить оператор delete [] с определенными аргументами

Мы пытаемся перегрузить оператор delete [] конкретными аргументами. Как правильно это называть? Мы используем компилятор GNU и получаем ошибки компилятора со всеми этими примерами:

#include<memory>
using namespace std;
typedef unsigned int P;

struct A{
    static allocator<A>m;
    P p;
    void*operator new[](size_t s){return m.allocate(s);}
    void operator delete[](void*p,int s){m.deallocate((A*)p,s);}
    void operator delete[](void*p,size_t t,int s){m.deallocate((A*)p,s);}
};

int main(){
    A*a=new A[10];
    //delete (5) []a;       //expected ',' before 'a'
    //delete[5]a;           //expected ';' before ']' token
    //delete[] (5) a;       //type ‘int’ argument given to ‘delete’, expected
    //delete[]a (5);        //a’ cannot be used as a function
    //delete[]((int)5)a;    //type ‘int’ argument given to ‘delete’, expected pointer
    //delete[]a((int)5);    //‘a’ cannot be used as a function
    return 0;
}

person ncomputers    schedule 27.09.2014    source источник
comment
Не оставляйте ошибки, которые вы получаете, загадкой, чтобы читатель мог их расшифровать; Отправьте их дословно вместе со своим вопросом.   -  person WhozCraig    schedule 28.09.2014
comment
Массивы удаляются следующим образом: delete[] a; - независимо от того, переопределили вы оператор delete[].   -  person Jonathan Potter    schedule 28.09.2014
comment
Вы знаете, что ваш распределитель выделяет в sizeof(A) раз больше памяти, чем должен? См .: en.cppreference.com/w/cpp/memory/allocator/allocate < / а>   -  person Deduplicator    schedule 28.09.2014


Ответы (2)


Для такого типа средства удаления размещения нет «синтаксического сахара».
Средство удаления размещения (например, то, что вы объявили) вызывается только тогда, когда конструктор, который был вызван новым размещением, выдает исключение.
Затем Программа вызовет соответствующий метод удаления размещения (такая же подпись) и попытается освободить специально выделенную память.

Если вы все же хотите вызвать этот метод, вам придется вызвать оператора вручную:

A::operator delete[](a, 5);

Вот хороший пример того, как это работает: http://en.cppreference.com/w/cpp/memory/new/operator_delete

Обратите внимание на исключение в деструкторе класса (оператор удаления вызывается после запуска исключения):

#include <stdexcept>
#include <iostream>
struct X {
    X() { throw std::runtime_error(""); }
    // custom placement new
    static void* operator new(std::size_t sz, bool b) {
        std::cout << "custom placement new called, b = " << b << '\n';
        return ::operator new(sz);
    }
    // custom placement delete
    static void operator delete(void* ptr, bool b)
    {
        std::cout << "custom placement delete called, b = " << b << '\n';
        ::operator delete(ptr);
    }
};
int main() {
   try {
     X* p1 = new (true) X;
   } catch(const std::exception&) { }
}
person Yochai Timmer    schedule 27.09.2014
comment
Стоит отметить, что этот ручной вызов не эквивалентен выражению удаления, даже если не учитывать дополнительный аргумент. delete[] p вызывает деструкторы, а затем вызывает operator delete[] функцию, но невозможно вручную вызвать правильное количество деструкторов, если вы не знаете размер массива. - person aschepler; 28.09.2014

TL; DR: пользовательские средства удаления размещения вызываются только в том случае, если конструктор объекта выдает и не может быть вызван без явного вызова оператора, например.

Class::operator delete[](a, 10, etc..);

Деструкторы в любом случае НЕ будут вызываться (еще одна задача, которую вам придется выполнить вручную).


Подробности:

Из cppreference

Перегрузки операторов delete и delete [] с дополнительными определяемыми пользователем параметрами («формы размещения», версия 11-12) могут быть объявлены в глобальной области как обычно и вызываются соответствующими формами размещения новых выражений, если конструктор выделяемого объекта вызывает исключение.

Стандартные формы размещения в библиотеке с оператором delete (9-10) не могут быть заменены и могут быть настроены только в том случае, если новое выражение размещения не использует синтаксис :: new, путем предоставления зависящего от класса удаления размещения (17,18) с соответствующая подпись: void T :: operator delete (void *, void *) или void T :: operator delete [] (void *, void *).

struct A{
    void* operator new[](std::size_t s){
        cout << "allocation 1" << endl;
        ...
        return ptr;
        }
    void* operator new[](std::size_t s, int){
        cout << "allocation 2" << endl;
        ...
        return ptr;
        }
    void operator delete[](void* s, std::size_t ){
        cout << "deallocate 1" << endl;
        ...
    }
    void operator delete[](void* s, std::size_t , int ){
        cout << "deallocate 2" << endl;
        ...

    }
};

int main(){
    A*a=new A[10];
    delete[] a;
    A*b=new(5) A[10];
    A::operator delete[](b,sizeof(b)/sizeof(A*),5); // You'll have to call it manually!
    return 0;
}
person Marco A.    schedule 27.09.2014