Каков полный список действий, выполняемых путем размещения новых в C ++? - PullRequest
7 голосов
/ 23 июня 2009

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

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

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

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

Ответы [ 3 ]

6 голосов
/ 23 июня 2009

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

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

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

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

  1. виртуальные базовые классы в порядке объявления
  2. невиртуальные базовые классы в порядке объявления
  3. члены класса в порядке объявления
  4. сам конструктор класса
4 голосов
/ 23 июня 2009

установить указатель vtable соответственно

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

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

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

0 голосов
/ 18 апреля 2017

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...