Переопределяющий оператор new / delete в производном классе - PullRequest
6 голосов
/ 22 июня 2011

У меня есть абстрактный класс без сохранения состояния, от которого наследуются различные конкретные классы. Некоторые из этих производных классов также не имеют состояния. Поскольку многие из них создаются во время выполнения, я бы хотел сэкономить память и накладные расходы, поскольку все производные классы без сохранения состояния эмулируют одноэлементный, переопределяя оператор new () / delete (). Упрощенный пример будет выглядеть примерно так:

#include <memory>

struct Base {
  virtual ~Base() {}
 protected:
  Base() {}   // prevent concrete Base objects
};

struct D1 : public Base {  // stateful object--default behavior
  int dummy;
};

struct D2 : public Base {  // stateless object--don't allocate memory
  void* operator new(size_t size)
  {
    static D2 d2;
    return &d2;
  }
  void operator delete(void *p) {}
};

int main() {
  Base* p1 = new D1();
  Base* p2 = new D1();
  Base* s1 = new D2();
  Base* s2 = new D2();
  delete p1;
  delete p2;
  delete s1;
  delete s2;
  return 0;
}

Этот пример не работает: delete s2; не удается, потому что delete s1; вызвал ~Base(), что освободило общий Base в d2. Эту проблему можно решить, добавив тот же трюк с перегрузкой new / delete в Base. Но я не уверен, что это самое чистое или даже правильное решение (valgrind не жалуется, FWIW). Буду признателен за совет или критику.

edit: на самом деле, ситуация хуже. Базовый класс в этом примере не является абстрактным, как я утверждал. Если это сделано абстрактно, посредством добавления чисто виртуального метода, то я больше не могу применять трюк переопределения new / delete, потому что у меня не может быть статической переменной типа Base. Поэтому у меня нет решения этой проблемы!

Ответы [ 2 ]

2 голосов
/ 22 июня 2011

Вы просто не можете этого сделать - это нарушило бы требование «идентичности объекта», которое гласит, что каждый объект должен иметь свой собственный адрес .Вы должны выделить отдельный блок памяти для каждого объекта - это можно сделать довольно быстро, если вы переопределите operator new, чтобы использовать быстрый распределитель блоков, специально предназначенный для объектов фиксированного размера.

1 голос
/ 22 июня 2011

Я бы сказал, что лучшее решение здесь - сделать ваш производный класс настоящим синглтоном.Сделайте ваш производный конструктор частным и просто предоставьте статический метод Base * getInstance (), который либо создает требуемый объект, либо возвращает статический экземпляр.Таким образом, единственный способ получить объект D1 будет через этот метод, так как вызов нового D1 будет недопустимым.

...