Я знаю, что значение данного this не может быть определено во время компиляции. Мне остается только гадать, что после выделения и создания данного объекта значение this кэшируется, или существует буквально оценка времени выполнения выражения при каждом использовании? Вот конкретный пример, который мотивирует мой вопрос. Имейте в виду, что это нарушает все доктрины ООП и функции защиты, которые стремится поддерживать С ++.

int main()
{
    string s1 = string("I am super a super long string named s1, and won't be SSO");
    string s2 = string("I am super a super long string named s2, and won't be SSO");

    byte* s1interface = reinterpret_cast<byte*>(&s1);
    byte* s2interface = reinterpret_cast<byte*>(&s2);

    static_assert(sizeof s1 == sizeof s2);

    for(int offset(0); offset < sizeof s1; ++offset)
    {
        *(s1interface + offset) ^= *(s2interface + offset);
        *(s2interface + offset) ^= *(s1interface + offset);
        *(s1interface + offset) ^= *(s2interface + offset);
    }

    cout << s1 << '\n' << s2 << "\n\n\n";

    return 0;
}
//outputs:
//I am super a super long string **named s2**, and won't be SSO
//I am super a super long string **named s1**, and won't be SSO
//(The emphasis on the output strings was added by me to highlight the identity change)

Я хочу начать с того, что эта программа не только компилируется, но и последовательно выдает этот результат. Мой вопрос не основан на том, почему и как это работает.

На мой взгляд, любые внутренние переменные, даже те, которые управляют памятью кучи, будут трансплантированы, как только объекты будут (повторно) полностью сформированы. Однако я представляю себе гипотетический сценарий, в котором this запрашивается объектом, а затем сохраняется внутри. После операции трансплантации объекта &me не будет совпадать с this, который был запрошен и сохранен при первоначальном построении, что серьезно повредит любые операции, использующие this вместе с любым отражением адреса во время выполнения. Хотя этого никогда не следует делать, и все ставки отменены, если кто-то осмелится сделать что-то настолько отвратительное с каким-либо предметом, принадлежащим им или иным, но Стандарт требует постоянной оценки this, или только для того, чтобы this сделать что он говорит в предположении, что объект будет занимать только то место, куда он помещен?

РЕДАКТИРОВАТЬ: Позвольте мне объяснить это по-другому. Если во время выполнения объект имеет скрытый и внутренний this, который записывается после того, как он выделен, и все последующие чтения this читают сохраненное значение после трансплантат &object и this не будут одинаковыми. Это явно не то, как это реализовано моим компилятором, но я хочу знать, было ли это соответствием или удачей.

1
schulmaster 21 Сен 2018 в 01:04

2 ответа

Лучший ответ

Поэтому я обратился к Стефану Лававеджу (веб-сайт Стефана), который поддерживает реализацию стандартной библиотеки для Microsoft, с этот вопрос. Я отправлю его ответ ниже. Я хочу отметить, что пользователь HAL9000 был по существу прав со своим ответом, но, поскольку Стефан был настолько подробным, я опубликую его и в конечном итоге обозначу его как официальный ответ ( это сложно чтобы получить более официальную информацию, чем слова кого-то, кто поддерживает реализацию Стандарта Большой тройки ). Если вы найдете этот ответ информативным, ответ HAL9000 содержит наглядный пример, подтверждающий эту идею.

Слова Стефана:

Вы не должны думать об указателе «this» как о хранящемся внутри объекта. Ментальная модель с неявными параметрами является наиболее точной. Когда функция x () вызывает функцию-член Meow :: y () для объекта Meow m, x () уже должна знать адрес m. Это может быть локальная переменная (x () знает, где в стеке находятся все ее локальные переменные), это может быть указатель с разыменованием (если m равно * ptr, ptr указывает на m), он может быть передан по ссылке (ссылки не являются указателями, но фактически имеют ту же информацию о местоположении, что и указатели), это может быть элемент массива (если m равно arr [idx], тогда arr + idx указывает на m) и т. д. Итак, Meow :: y ( ) будет неявно передан адрес m, который становится this внутри функции-члена.

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

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

Надеюсь, это поможет, STL

1
schulmaster 22 Сен 2018 в 08:08

Значение this никогда не «запрашивается» объектом. Он передается (нестатическим) объектным методам как неявный параметр.

Предположим, у вас есть этот код на C ++:

#include <stdio.h>

class mystring
{
public:
   char *data;  
   void print();
};

void mystring::print() 
{
   fputs(this->data, stdout);
}

void
main()
{
   mystring s = {"Hello World"};  

   s.print();
}

Теперь похоже, что метод print не принимает никаких параметров, но на самом деле принимает указатель на объект s. Таким образом, компилятор сгенерирует код, эквивалентный этой программе на языке C.

#include <stdio.h>

struct mystring
{
   char *data;  
};

void mystring_print(struct mystring *this) 
{
   fputs(this->data, stdout);
}

void
main()
{
   mystring s = {"Hello World"};  

   mystring_print(&s);
}

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

2
HAL9000 20 Сен 2018 в 22:34