Есть ли способ предотвратить динамическое выделение класса?

#c #dynamic-allocation

#c #dynamic-allocation

Вопрос:

Я использую базовый класс C и подклассы (давайте назовем их A и B для ясности) в моей встроенной системе.

Это критично ко времени и пространству, поэтому мне действительно нужно, чтобы оно было минимальным.

Компилятор жалуется на отсутствие виртуального деструктора, что я понимаю, потому что это может доставить вам неприятности, если вы выделите B* , а затем удалите указатель как экземпляр A* .

Но я никогда не собираюсь выделять какие-либо экземпляры этого класса. Есть ли способ, которым я могу перегрузить operator new() так, чтобы он компилировался, если динамического выделения ни для одного из классов нет, но вызывает ошибку компилятора, если конечный пользователь пытается выделить новые экземпляры A или B?

Я ищу аналогичный подход к распространенной технике «отравления» конструкторов автоматического копирования компилятора с помощью частных конструкторов. (например http://channel9.msdn.com/Forums/TechOff/252214-Private-copy-constructor-and-private-operator-C )

Комментарии:

1. Последняя часть вашего поста заставляет меня задуматься, нужна ли вам реализация одноэлементного шаблона. en.wikipedia.org/wiki/Singleton_pattern

2. @Rycul: Спасибо, это не синглтоны, просто в небольших встроенных системах мы склонны делать почти все со статическим или стековым распределением.

3. Просто из любопытства. Я не понимаю, зачем вам вообще нужен виртуальный деструктор? То, что вы производите, не означает, что вам нужен виртуальный деструктор. Есть ли у вас какая-либо другая виртуальная функция? Как вы собираетесь использовать такую функцию, если вы не собираетесь использовать ее в динамической памяти в первую очередь?

4. @alfC: перечитайте: «Компилятор жалуется на отсутствие виртуального деструктора».

5. p.s. не возлагайте больших ожиданий на ответы на комментарии по вопросам, которые были заданы много лет назад

Ответ №1:

Вы можете отравить operator new точно так же, как вы можете скопировать конструктор. Просто убедитесь, что не отравляете размещение new. Виртуальный деструктор все равно был бы хорошей рекомендацией.

 int main() {
    char data[sizeof(Derived)];
    if (condition)
        new (data) Derived();
    else
        new (data) Base();
    Base* ptr = reinterpret_cast<Base*>(amp;data[0]);
    ptr->~Base();
}
  

Комментарии:

1. «Виртуальный деструктор все равно был бы хорошей рекомендацией». — было бы, за исключением того, что без динамического выделения памяти он не будет использоваться, а затраты на память в этом классе слишком высоки. (в противном случае я бы просто вставил туда пустой виртуальный деструктор и покончил с этим.)

2. @Jason S: Я бы не был так уверен в этом. Динамическое выделение не всегда означает просто кучу — это также может означать размещение нового. Я мог бы легко создать пример, который не использовал бы никакого динамического выделения памяти и по-прежнему зависел бы от виртуального деструктора. Если вы абсолютно не можете его использовать, то отравите размещение new тоже.

3. знаете ли вы какие-либо «простые» случаи, в которых используется placement new без динамического выделения памяти? Это процессор с относительно ограниченной памятью нет стандартной библиотеки (поэтому STL здесь нет; мы не используем стеки, очереди или что-то еще).

4. @Jason: Только что опубликовал один. Я думаю, что если вы точно знаете, что вы пишете каждую строку в своей программе, вы могли бы избежать этого или просто отравить размещение new, но этот код не определен без виртуального деструктора.

5. Ну, я полагаю, я мог бы также сделать деструктор приватным.

Ответ №2:

 class A
{
private:
    void *operator new(size_t);
    ...
};
  

Пропуски относятся к другим переопределениям operator new и остальной части класса.

Комментарии:

1. или void* operator new(size_t) = delete;

2. Я все еще могу это сделать char* addr = new char[sizeof(A)]; A* a = ::new (addr) A; . Как я могу также запретить всем новым операторам размещения?

Ответ №3:

Просто сделайте operator new частным