Каков полный список действий, выполняемых при размещении new в C++?

В этом вопросе создается обсуждается фабричный метод, когда компилятор не поддерживает new и размещение new. Очевидно, что какое-то подходящее решение может быть создано с помощью malloc(), если все необходимые шаги, выполняемые размещением new, каким-то образом воспроизводятся.

Что делает размещение new — я постараюсь перечислить и надеюсь ничего не пропустить — кроме следующего?

  • рекурсивно вызывать конструкторы для всех базовых классов
  • вызывать конструкторы и инициализаторы (если есть) для всех переменных-членов
  • установите указатель vtable соответственно.

Какие еще действия?


person sharptooth    schedule 23.06.2009    source источник


Ответы (3)


Размещение new делает все то же самое, что и обычное new, за исключением выделения памяти.

Я думаю, вы, по сути, поняли, что происходит, с некоторыми небольшими уточнениями:

  • очевидно, конструктор самого класса также вызывается
  • Указатели vtable инициализируются как часть вызовов конструктора, а не отдельно. Следствием этого является то, что частично созданный объект (например, исключения, созданные в конструкторе) имеет свою виртуальную таблицу, установленную до точки, к которой приступила конструкция.

Порядок построения/инициализации следующий:

  1. виртуальные базовые классы в порядке объявления
  2. невиртуальные базовые классы в порядке объявления
  3. члены класса в порядке объявления
  4. сам конструктор класса
person laalto    schedule 23.06.2009

установить указатель vtable соответствующим образом

Эта часть почти полностью определяется реализацией. Ваш компилятор может не использовать vtables. Может быть несколько указателей vtable или один или несколько указателей на вещи, которые не являются vtables. Множественное наследование всегда интересно, как и виртуальные базовые классы. Не гарантируется возможность копирования этих метаданных с помощью memcpy в другой объект, поэтому указатель(и) не обязательно должен быть абсолютным. Там могут быть смещения, которые относятся к самому указателю объекта.

IIRC обычно происходит так: вызывается конструктор базового класса, затем указатель vtable устанавливается на базовый класс, затем вызывается конструктор первого производного класса и т. д. Это делается для того, чтобы удовлетворить требования спецификации относительно того, что происходит, когда виртуальная функция вызывается в конструкторе. Насколько я помню, в стандарте нет "списка действий", только определенный порядок инициализации.

Поэтому невозможно обобщить, что делает реализация, тем более что то, что у вас есть, не является реализацией стандарта С++. Если он срезает углы, опуская «новое», по-видимому, по уважительной причине, потому что считает, что вы не должны использовать его на целевой платформе, то кто знает, какие еще правила языка он игнорирует. Если бы можно было смоделировать «новое» с помощью malloc и небольшого нажатия указателя, то с какой стати компилятор просто не реализует новое? Я думаю, вам нужно задавать вопросы, помеченные вашим конкретным компилятором и платформой, чтобы любой специалист по вашему компилятору мог ответить.

person Steve Jessop    schedule 23.06.2009

Ответ @laalto в целом верен. Однако одно исключение подтверждает правило.

Указатели vtable инициализируются как часть вызовов конструктора, а не отдельно.

Компилятор Microsoft C++ знает так называемые локальные vftables, то есть vftables являются локальными для DLL и будут клонированы для каждого импортируемого класса. Это связано с тем, что компилятор хочет предоставить модифицированный деструктор, который обертывает исходный (например, здесь).

Всякий раз, когда вы создаете объект импортированного класса, компилятор генерирует код, который заменяет исходный указатель(и) vftable локальным(и) указателем(ями) после вызова конструктора. Этот код также присутствует в размещении новых звонков.

Существует еще один обходной путь, помимо упомянутых в посте выше. Этот обходной путь не требует изменения исходных файлов заголовков. Пожалуйста, посмотрите здесь: https://godbolt.org/g/YQsffY

person eel76    schedule 18.04.2017