2009-06-23 5 views
7

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

Что делает размещение do - Я попытаюсь перечислить и надеюсь не пропустить что-либо - кроме следующего?

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

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

ответ

6

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

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

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

Порядок строительства/инициализации выглядит следующим образом:

  1. виртуальных базовых классов в порядке декларации
  2. невиртуальными базовые классы в порядке декларации
  3. членов класса в декларации порядка
  4. класс конструктора само по себе
+0

+1 для понимания виртуального базового класса строительства –

4

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

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

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

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

0

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

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

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

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

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