Почему виртуальный метод генерирует неопределенную ссылку на _sbrk?

Это изящно компилируется:

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;
}

2

Решение

Производные классы могут иметь свои собственные оператор удаления. Эта функция используется очень редко — почти никогда в моем опыте. Виртуальный деструктор позволяет вызывать правильный оператор 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 оператор вызывается.

3

Другие решения

Я почти уверен, что вызывается _sbrk, потому что вы используете виртуальные функции, пытаясь найти путь к коду, чтобы вызвать исключение для вызова «чисто виртуальной функции».

загляните в свой файл карты и посмотрите, что вызывает _sbrk, как он вызывается и т. д., пока не найдете рут.

см. этот пост с дополнительной информацией: Объявление абстрактного класса (чисто виртуальный метод) существенно увеличивает размер двоичного файла

постскриптум vtables не требует динамического выделения памяти

-1

Раньше я думал, что vtable размещается где-то статически и не требует malloc.

Не уверен, откуда вы взяли это предположение:

  • Нет гарантий того, как реализованы vtables, и в стандартах не говорится, что динамическая диспетчеризация вообще должна быть реализована с использованием vtables. Это просто самый распространенный метод.
  • В вашем вопросе отсутствуют какие-либо доказательства того, что _sbrk на самом деле втягивается, потому что деструктор virtual

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

-2
По вопросам рекламы [email protected]