#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 частным