Подтвердить что ты не робот

Когда указатель "this" инициализирован в С++?

Привет У меня есть вопрос о указателе this, когда объект сконструирован, когда он инициализируется? Что означает, когда я могу его использовать? Виртуальная таблица построена в конструкторе, то же самое с указателем this?

Например, у меня есть такой код. Вывод равен 8. Означает ли это, что до ввода конструктора указатель this уже инициализирован?

class A{
   public:
     A() { cout<<sizeof(*this);}
     int i;
     int *p; 
};

int main() {      
    A a; 
}

Если это правда, что еще произойдет до ввода конструктора?

Если это неверно, когда инициализирован указатель this?

4b9b3361

Ответ 1

Указатель this не является членом объекта или класса - это неявный параметр для метода, который вы вызываете. Таким образом, он прошел так же, как и любой другой параметр, за исключением того, что вы не запрашиваете его напрямую.

В приведенном выше примере конструктор представляет собой специальный метод, который, в свою очередь, является особым видом функции. Когда вы строите объект, компилятор выделяет для него память (в этом случае в стеке, поскольку a является локальной переменной в функции main, а затем автоматически вызывает конструктор для инициализации объекта.

Как часть вызова конструктора, неявный параметр this - указатель на ваш объект - передается как параметр.

В методе со следующей сигнатурой...

void MyMethod (const int* p) const;

есть два параметра, оба указателя. Там явный параметр p и неявный параметр this. const в конце строки указывает, что this является указателем const, так как предыдущий указывает, что p является указателем const. Необходимость в этом специальном синтаксисе существует только потому, что this передается неявно, поэтому вы не можете указывать константу обычным образом, как с другими параметрами.

"Статический" метод не имеет неявного параметра "this" и также не может напрямую обращаться к членам объекта - не может быть определенного объекта, связанного с вызовом. В основном это стандартная функция, а не метод, за исключением доступа к частным членам (при условии, что он может найти объект для доступа).

Как указывает Стив Фаллоус, sizeof (this) известен во время компиляции, потому что это тип указателя, и все указатели (* 1) имеют одинаковое значение sizeof. "8", который вы видите, подразумевает, что вы компилируете для 64-битной платформы. this можно использовать в данный момент - он указывает на действительную память, и все члены завершили свои вызовы конструктора. Однако это не обязательно полностью инициализировано - вы все равно находитесь в вызове конструктора.

ИЗМЕНИТЬ

* 1 - строго, это может быть неверно, но компилятор знает, какой тип указателя он имеет в виду здесь, даже если значение неизвестно до выполнения.

Ответ 2

Указатель this не сохраняется. Когда конструктор вызывается для объекта, который занимает определенную ячейку памяти, это местоположение передается как параметр для конструктора и других функций-членов.

Если this будет храниться внутри объекта, как получить этот указатель? Правильно, вам снова понадобится указатель this:)

Ответ 3

sizeof (* this) известен во время компиляции. Таким образом, инструкция cout ничего не сообщает об инициализации этого.

Учитывая, что конструктор может немедленно начать доступ к элементам объекта, это явно инициализируется до начала конструктора.

Что еще происходит перед конструктором? Ну может быть что угодно. Я не думаю, что стандарт ограничивает возможности компилятора. Возможно, вам следует указать что-либо, о чем вы думаете, может случиться.

Ответ 4

Виртуальная таблица построена в конструкторе, то же самое с этим указателем?

Виртуальная таблица НЕ строится в конструкторе.
Как правило, одна глобальная v-таблица разделяется всеми экземплярами одного и того же класса, и каждый отдельный класс имеет свою собственную глобальную v-таблицу.
V-таблица известна во время компиляции и "построена" в программе время загрузки.

Указатель this "сконструирован" (я думаю, что "выделенный" является лучшим термином) во время распределения, то есть после global new operator, и до ввода конструктора.

В случаях, когда объект распределяется по стекам вместо выделенной кучи, глобальный new не вызывается, но this по-прежнему доступен в результате выделения стекового пространства, которое находится непосредственно перед вводом конструктора.

Экземпляр vptr назначается после выделения памяти объекта и непосредственно перед вызовом конструктора.

Ответ 5

Означает ли это, что до ввода конструктора указатель this уже инициализирован?

Да, значение указателя this известно, прежде чем конструктор будет даже вызываться. Это значение доступно через ключевое слово this внутри конструкторов, конструктор списки инициализации, деструкторы, методы-члены. Ключевое слово this ведет себя на поверхности как переменная метода (типа указателя), но не является одним; он обычно находится в регистре (ecx на платформах x86), и вы, как правило, не сможете скомпилировать код типа &this.

Что еще должно произойти до ввода конструктора

По крайней мере, что касается указателя this, первое, что происходит (если не использовать размещение new), выделение памяти, в конечном счете указанное на this, будь то в стеке (например, в вашем примере) или в куче (используя new.) В этот момент указатель this известен. Затем конструкторы по умолчанию или явно указанные конструкторы (через списки инициализации конструктора) затем называются в базовых классах (если они есть) и на вашем классе не POD переменные участника (если есть). Указатель класса vtable также устанавливается перед этой точкой, если ваш класс содержит виртуальные методы или деструктор. Затем вызывается тело конструктора вашего класса, если оно есть. (Конструктор называется рекурсивно, т.е. Когда вызывается конструктор базового класса, вызываются последние конструкторы базового класса, за которым следуют конструкторы-члены не-POD, при этом устанавливается указатель базового класса vtable, за которым следует тело конструктора класса.)

Ответ 6

Этот указатель является первым аргументом для каждого вызова класса, включая конструктор.

Когда вызывается метод класса, адрес класса переносится в последний стек (предполагается, что здесь вызывается соглашение cdecl). Это считывается обратно в регистр для использования в качестве этого указателя.

Конструкторы фактически называются, как если бы они были обычными функциями-членами.

У вас нет виртуального конструктора, потому что конструктор отвечает за установку члена vtable.

Ответ 7

Как уже указывал nobugz, ваш пример на самом деле не означает многого - sizeof дает свои результаты в зависимости от типа объекта, который вы передаете ему. Он не оценивает свой операнд во время выполнения.

Тем не менее, да, this инициализируется перед входом в ctor. В основном, компилятор выделяет пространство для объекта (в стеке, если объект имеет автоматическую продолжительность хранения или использует ::operator new, если он имеет динамическую продолжительность хранения). При входе в ctor ctors для базовых классов (если они есть) уже завершены. Когда вы вызываете ctor, this указывает адрес памяти, выделенной для объекта.

Ответ 8

этот начинает указывать на текущий объект, и все члены и базовые классы инициализируются до того, как вы введете тело конструктора.

Поэтому вы можете указать указатель на этот в списке инициализации, но получатель не должен делать ничего другого, кроме сохранения его, поскольку экземпляр с указателем не может быть полностью сконструирован в то время.

#include <iostream>

class B;

class A
{
    B* b_ptr;
public:
    A(B* b);
};

class B
{
    A a;
    int i;
public:
    B(): a(this), i(10) {}
    void foo() const { std::cout << "My value is " << i << '\n'; }
};

A::A(B* b):
    b_ptr(b) //Ok to store
{
    b_ptr->foo(); //not OK to use, will access initialized member
}

int main()
{
    B b;
}