подскажите пожалуйста... есть примерно такой код (этот образец не мой, взят из интернета, с форума на котором обсуждался подобный вопрос, но адекватное решение так и не было предложено): Код (Text): class MemPool { public: allocBlock(..); freeBlock(...); }; class MyObject { public: MyObject(); ~MyObject(); void* operator new(size_t size, MemPool* pool) { return pool->allocBlock(size);} void operator delete(void* ptr, MemPool* pool) { pool->freeBlock(ptr);} } int main() { MemPool myPool; // Все правильно и нормально MyObject* pObj = new (&myPool) MyObject(); // Тут возникает ошибка delete (&myPool) pObj; return 0; } я думаю, что по коду понятен смысл того, что я пытаюсь сделать... но не могу понять, что за проблема с оператором delete... как его правильно вызвать, чтобы был вызван деструктор класса, а затем перегруженный оператор delete класса? сразу обращаю ваше внимание на то, что хранить указатель на MemPool внутри класса и вызывать в delete нельзя, так как операторы new/delete всегда статические... и руками вызывать деструктор и затем перегруженный оператор чет не особо хочется))) видимо по стандарту так делать нельзя, да и гугл чет не помогает, что делает меня очень грустной пандой...
Скорее всего так происходит из-за того, что реально оператор delete вызывается кодом окружающим сам деструктор, ввиду возможного полиморфизма. "delete pObj;" на самом деле заменяется компилятором более сложной последовательностью вызовов. Если бы была возможность объявить любую сигнатуру, то это скорее всего повлекло бы проблемы с этим самым полиморфизмом. Так что нельзя. Но большой проблемы не вижу, есть масса других вариантов. Можно вызвать свою функцию удаления. ^)
Ой ахтунг, как бы не нарваться на двойной вызов деструктора. Не понятно зачем вызывать delete после вызова деструктора, тут или вообще ничего вызывать не надо или вызывать что-то другое.
спасибо всем за ответы... мне все же кажется странным, что размещающий оператор нельзя так просто вызвать вместе с деструктором объекта... но да ладно... если кому интересно, в итоге сделал создание объекта через статическую функцию Create, а удаление через виртуальную функцию Delete (там в коде получилось что-то типа эпического delete this, которое почему-то у многих программистов вызывает переполнение стека в голове)... так же пришлось перегрузить размещающий оператор new и запихнуть его в протектед, а в функции Create его вызывать, это было сделано для корректной настройки vtable в наследниках... и еще пришлось запихнуть конструкторы и оператор delete в протектед, чтобы вынудить программиста создавать и удалять экземпляры только функциями Create и Delete... но в целом такая схема выглядит вполне нормально и судя по тестам правильно работает)))
хех... интересный вариант) тут к сожалению статический mempool не прокатит, тк приложение многопоточное, а добавлять в класс mempool синхронизацию не особо хочется... сейчас для каждого отдельного потока генерируется свой mempool... тем более, у меня уже возникали проблемы про сборку синглтонов без CRT, как то не хочется этим заморачиваться... ЗЫ вообще я в доволен тем велосипедом, который изобрел... так что не переживайте)
Код (Text): pObj->~MyObject(); delete (my, &pool); у меня работает. Там все гладко проходит вроде, не?
это работает, но это не красиво... к сожалению нет... если о студии разговор, то компилятор желает вызывать atexit, оператор delete для статического синглтона.. если о мингв - то там еще побольше функций, которые придется самому писать, если собираешь без CRT...
Используй TLS. И еще: void* operator new(size_t size, MemPool* pool) { return pool->allocBlock(size);} // Все правильно и нормально MyObject* pObj = new (&myPool) MyObject(); Лучше так не делать, код плохо читаемый, надо видеть определение placement new что бы понять что делает new, по умолчанию он конструирует MyObject() в памяти занимаемой объектом myPool.
опять же при сборке без CRT придется самостоятельно реализовывать CRT-функции... для MinGW это __emutls_get_address: Код (Text): #include <windows.h> __thread const char* a = "Aaa"; __declspec(thread) const char* b = "Bbb"; int main() { MessageBoxA(NULL, a, b, MB_OK); return 0; }
Перегрузка Код (Text): void* operator new(size_t size, MemoryPool * lpPool) { return lpPool->alloc(size); } template<typename objtype> void operator delete(void* ptr, int pool/*MemoryPool * lpPool*/) { objtype * obj = (objtype *)ptr; obj->~objtype(); lpPool->free(obj); } Использование Код (Text): A * obj = new(&pool) A(); operator delete<A>(obj, 1);
ntkernelspawn веселый темплейт... непонятно, зачем в функцию int pool передавать?) имелся ввиду lpPool?
Вообще перегрузка delete это примерно как и delete и delete[], то есть плохо. Уж если и делать какие-то доп. функции, то тогда надо запрещать другую альтернативу.
вообще насколько я помню перегрузка одного из операторов new или одного из операторов delete требует перегрузки всех других аналогичных операторов в случае их использования)
Rel Да это хорошее правило, хоть и не обязательное. Но я писал о том, что выделяем одним оператором, а потом забываем каким надо освободить. ^)
По строкам кода - немного. Зато по потерям в быстродействии на синхронизацию и lock contention - очень даже. Аллокатор с локом на входе - это уже прошлый век.