Перегрузка операторов new/delete

Тема в разделе "LANGS.C", создана пользователем Rel, 19 мар 2011.

  1. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    подскажите пожалуйста... есть примерно такой код (этот образец не мой, взят из интернета, с форума на котором обсуждался подобный вопрос, но адекватное решение так и не было предложено):
    Код (Text):
    1. class MemPool
    2. {
    3. public:
    4. allocBlock(..);
    5. freeBlock(...);
    6. };
    7.  
    8. class MyObject
    9. {
    10. public:
    11. MyObject();
    12. ~MyObject();
    13.  
    14. void* operator new(size_t size, MemPool* pool)
    15. { return pool->allocBlock(size);}
    16. void operator delete(void* ptr, MemPool* pool)
    17. { pool->freeBlock(ptr);}
    18. }
    19.  
    20.  
    21. int main()
    22. {
    23. MemPool myPool;
    24.  
    25. // Все правильно и нормально
    26. MyObject* pObj = new (&myPool) MyObject();
    27.  
    28. // Тут возникает ошибка
    29. delete (&myPool) pObj;
    30.  
    31. return 0;
    32. }
    я думаю, что по коду понятен смысл того, что я пытаюсь сделать... но не могу понять, что за проблема с оператором delete... как его правильно вызвать, чтобы был вызван деструктор класса, а затем перегруженный оператор delete класса? сразу обращаю ваше внимание на то, что хранить указатель на MemPool внутри класса и вызывать в delete нельзя, так как операторы new/delete всегда статические... и руками вызывать деструктор и затем перегруженный оператор чет не особо хочется))) видимо по стандарту так делать нельзя, да и гугл чет не помогает, что делает меня очень грустной пандой...

    [​IMG]
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Скорее всего так происходит из-за того, что реально оператор delete вызывается кодом окружающим сам деструктор, ввиду возможного полиморфизма. "delete pObj;" на самом деле заменяется компилятором более сложной последовательностью вызовов.
    Если бы была возможность объявить любую сигнатуру, то это скорее всего повлекло бы проблемы с этим самым полиморфизмом. Так что нельзя. Но большой проблемы не вижу, есть масса других вариантов. Можно вызвать свою функцию удаления. ^)
     
  3. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ой ахтунг, как бы не нарваться на двойной вызов деструктора. Не понятно зачем вызывать delete после вызова деструктора, тут или вообще ничего вызывать не надо или вызывать что-то другое.
     
  4. 737061

    737061 New Member

    Публикаций:
    0
    Регистрация:
    3 авг 2007
    Сообщения:
    74
    вызов деструктора не освобождает память занимаемую классом.
     
  5. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Потому что гладиолус.
     
  6. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    спасибо всем за ответы... мне все же кажется странным, что размещающий оператор нельзя так просто вызвать вместе с деструктором объекта... но да ладно... если кому интересно, в итоге сделал создание объекта через статическую функцию Create, а удаление через виртуальную функцию Delete (там в коде получилось что-то типа эпического delete this, которое почему-то у многих программистов вызывает переполнение стека в голове)... так же пришлось перегрузить размещающий оператор new и запихнуть его в протектед, а в функции Create его вызывать, это было сделано для корректной настройки vtable в наследниках... и еще пришлось запихнуть конструкторы и оператор delete в протектед, чтобы вынудить программиста создавать и удалять экземпляры только функциями Create и Delete... но в целом такая схема выглядит вполне нормально и судя по тестам правильно работает)))
     
  7. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Rel
    В new, в начале памяти положить указатель на менеджер.
     
  8. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    хех... интересный вариант)

    тут к сожалению статический mempool не прокатит, тк приложение многопоточное, а добавлять в класс mempool синхронизацию не особо хочется... сейчас для каждого отдельного потока генерируется свой mempool... тем более, у меня уже возникали проблемы про сборку синглтонов без CRT, как то не хочется этим заморачиваться...

    ЗЫ вообще я в доволен тем велосипедом, который изобрел... так что не переживайте)
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Код (Text):
    1.     pObj->~MyObject();
    2.     delete (my, &pool);
    у меня работает.

    Там все гладко проходит вроде, не?
     
  10. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    это работает, но это не красиво...

    к сожалению нет... если о студии разговор, то компилятор желает вызывать atexit, оператор delete для статического синглтона.. если о мингв - то там еще побольше функций, которые придется самому писать, если собираешь без CRT...
     
  11. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Используй TLS.


    И еще:

    void* operator new(size_t size, MemPool* pool) { return pool->allocBlock(size);}

    // Все правильно и нормально
    MyObject* pObj = new (&myPool) MyObject();

    Лучше так не делать, код плохо читаемый, надо видеть определение placement new что бы понять что делает new, по умолчанию он конструирует MyObject() в памяти занимаемой объектом myPool.
     
  12. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    опять же при сборке без CRT придется самостоятельно реализовывать CRT-функции... для MinGW это __emutls_get_address:
    Код (Text):
    1. #include <windows.h>
    2.  
    3. __thread           const char* a = "Aaa";
    4. __declspec(thread) const char* b = "Bbb";
    5.  
    6. int main()
    7. {
    8.     MessageBoxA(NULL, a, b, MB_OK);
    9.     return 0;
    10. }
     
  13. ntkernelspawn

    ntkernelspawn New Member

    Публикаций:
    0
    Регистрация:
    17 дек 2010
    Сообщения:
    61
    Перегрузка
    Код (Text):
    1. void* operator new(size_t size, MemoryPool * lpPool)
    2. {
    3.     return lpPool->alloc(size);
    4. }
    5.  
    6. template<typename objtype>
    7. void operator delete(void* ptr, int pool/*MemoryPool * lpPool*/)
    8. {
    9.     objtype * obj = (objtype *)ptr;
    10.     obj->~objtype();
    11.     lpPool->free(obj);
    12. }
    Использование
    Код (Text):
    1. A * obj = new(&pool) A();
    2.  
    3. operator delete<A>(obj, 1);
     
  14. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    ntkernelspawn
    веселый темплейт... непонятно, зачем в функцию int pool передавать?) имелся ввиду lpPool?
     
  15. ntkernelspawn

    ntkernelspawn New Member

    Публикаций:
    0
    Регистрация:
    17 дек 2010
    Сообщения:
    61
  16. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Вообще перегрузка delete это примерно как и delete и delete[], то есть плохо.
    Уж если и делать какие-то доп. функции, то тогда надо запрещать другую альтернативу.
     
  17. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    вообще насколько я помню перегрузка одного из операторов new или одного из операторов delete требует перегрузки всех других аналогичных операторов в случае их использования)
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Rel
    Да это хорошее правило, хоть и не обязательное. Но я писал о том, что выделяем одним оператором, а потом забываем каким надо освободить. ^)
     
  19. Ursus

    Ursus Member

    Публикаций:
    0
    Регистрация:
    15 мар 2006
    Сообщения:
    238
    Адрес:
    Russia
    По строкам кода - немного.
    Зато по потерям в быстродействии на синхронизацию и lock contention - очень даже.
    Аллокатор с локом на входе - это уже прошлый век.