Это изящно компилируется:
class dummy {
};
Это жалуется на неопределенную ссылку на _sbrk:
class dummy {
virtual ~dummy();
};
Почему виртуальный метод генерирует неопределенную ссылку на _sbrk
?
Раньше я думал, что vtable
размещается где-то статически и не требует malloc
,
Составитель: arm-none-eabi-gcc 8.0.0
с недавним newlib
, Составлено с -fno-rtti -fno-exceptions -fno-unwind-tables
,
Тестовая программа (boot
как main
):
class base {
public:
virtual ~base();
};
class dummy : public base {
public:
~dummy();
};
base::~base() {
__BKPT();
}
dummy::~dummy() {
__BKPT();
}
extern "C" void _sbrk() {
__BKPT();
}
void boot() {
for(;;) {
base b;
dummy d;
}
return 0;
}
Производные классы могут иметь свои собственные оператор удаления. Эта функция используется очень редко — почти никогда в моем опыте. Виртуальный деструктор позволяет вызывать правильный оператор delete при использовании выражения delete (delete p
).
Компилятор определенно сгенерировал виртуальный деструктор с удалением, который вызывает оператор удаления класса, который почти во всех случаях оказывается глобальным оператором удаления (::operator delete
) но это также может быть переопределено локальным оператором, определенным в классе.
Так как delete
никогда не используется (для этого конкретного типа), что автоматически генерируемая виртуальная функция destructor-with-delete никогда не вызывается, но это все еще упоминается в vtable. Если у вас нет соответствующей поддержки компилятора и компоновщика, в виртуальной таблице есть ссылки на каждую виртуальную функцию, а виртуальная таблица используется, по крайней мере, в конструкторах класса, поэтому любой созданный объект будет нуждаться в каждой виртуальной функции этого класса.
Если у вас есть соответствующая поддержка компоновщика, вы можете использовать только виртуальные функции с именами; другие записи vtable могут быть нулевыми, поскольку на них никогда не ссылаются.
РЕДАКТИРОВАТЬ: Стандартная цитата
От [Class.dtor]/ 12:
На точка определения виртуального деструктора (включая
неявное определение), функция освобождения без массива
определяется как будто для выражениеdelete this
появляется в
не виртуальный деструктор класса деструктора (см. [expr.delete]).
Если поиск не удается или если функция освобождения удалена
По определению, программа плохо сформирована. [Примечание: это гарантирует, что
функция освобождения, соответствующая динамическому типу объекта
доступно для выражения удаления ([class.free]). — конец примечания]
«виртуальный деструктор» … определяется как если бы «не виртуальный деструктор» содержал выражение это словоблудие, которое может быть трудно декодировать: поскольку деструктор является виртуальным, почему мы говорим о виртуальном деструкторе? (Я должен был прочитать вышеупомянутый стандартный текст несколько раз.)
Другой способ увидеть это с точки зрения возможной реализации (некоторые реализации использовали именно для этого):
Каждый деструктор фактически принимает параметр bool deallocate
и компилятор добавляет код:
if (deallocate)
delete this;
непосредственно перед концом тела деструктора, и все деструкторы вызываются с false
аргумент, кроме одного полного объекта, когда delete
оператор вызывается.
Я почти уверен, что вызывается _sbrk, потому что вы используете виртуальные функции, пытаясь найти путь к коду, чтобы вызвать исключение для вызова «чисто виртуальной функции».
загляните в свой файл карты и посмотрите, что вызывает _sbrk, как он вызывается и т. д., пока не найдете рут.
см. этот пост с дополнительной информацией: Объявление абстрактного класса (чисто виртуальный метод) существенно увеличивает размер двоичного файла
постскриптум vtables не требует динамического выделения памяти
Раньше я думал, что vtable размещается где-то статически и не требует malloc.
Не уверен, откуда вы взяли это предположение:
_sbrk
на самом деле втягивается, потому что деструктор virtual
И я действительно не понимаю цели вопроса: если вы хотите использовать виртуальные методы, вам все равно нужно иметь функции динамического выделения памяти.