Как переназначить указатель this внутри функции-члена объекта? - PullRequest
6 голосов
/ 12 января 2010

У меня есть интересный вопрос об указателях C ++.

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

Так что это ситуация. У меня есть класс C ++ TestClass, и у меня есть указатель A этого типа:

TestClass* A = new TestClass();

Среди прочего TestClass имеет эту функцию:

void TestClass::Foo(){
    TestClass* B = new TestClass();
    ...
}

Эта функция создает объект B того же типа и заполняет его некоторыми данными.

В конце этой функции я хочу, чтобы указатель A указывал на объект B. В любом месте за пределами этой функции это будет выглядеть так: A=B; внутри этой функции это может выглядеть как this = B
Но, как вы знаете, вы не можете переназначить указатель «this».

Возможные решения:

  1. Копировать память:

    memcpy(this, B, sizeof(TestClass));
    

    Этот метод работает правильно. Функция копирует каждый бит объекта B в объект A.
    Проблема: если TestClass - большой объект (и он есть), это создает значительные потери производительности для нескольких вызовов Foo.

  2. Вернуть указатель B из функции и сделать что-то вроде этого

    Temp = A;
    A=A->Foo();
    freeMemory(Temp);
    

    Но этот код выглядит глупо, и это делает функцию Foo очень сложной для использования.

Итак, вопрос в том, как я могу сделать this = B внутри функции-члена, не копируя целые объекты?

Ответы [ 7 ]

13 голосов
/ 12 января 2010

Используйте дополнительный уровень косвенности.Ваш TestClass может иметь указатель, который указывает на класс, который содержит все его данные.

class TestClass
{
private:
  TestClassData* m_data;

};

void TestClass::Foo()
{
  TestClassData* B = new TestClassData();
  ... 
  delete m_data;
  m_data = B;
} 

Просто убедитесь, что ваш operator== возвращает true, если содержимое m_data равно.

7 голосов
/ 12 января 2010

как я могу это сделать = B

Вы не можете.

Одно из рабочих решений: memcpy (this, B, sizeof (TestClass)); этот метод работает правильно.

Если TestClass не является POD, эта функция не работает. Например, вы не можете создавать объекты с виртуальными функциями. Вы сдуете стол.

6 голосов
/ 12 января 2010

Внутри вашей функции вы можете сделать

*this = B;

Которые выполняют практически одинаковую операцию копирования.
Или вы также можете объявить

Foo(TestClass &X);

И переназначить X-адрес внутри.

4 голосов
/ 12 января 2010

Вы не можете. this определяется стандартом как TestClass * const.

Чтобы понять почему, подумайте об этом коде:

int main() {
   TestClass A;
   A.Foo();
   return 0;
}

A в стеке. Как сделать так, чтобы объект в стеке ссылался на что-то еще?

2 голосов
/ 12 января 2010

Проблема в том, что многие указатели, а не только A, могут указывать на старый объект. Указатель this не A, хотя A содержит его копию. Единственный способ сделать это: 1. переназначить A или 2. создать новый тип указателя, который добавляет уровень косвенности к вашему объекту, чтобы вы могли заменить его, не подозревая.

1 голос
/ 12 января 2010

То, что вы делаете, нехорошо.

Во-первых, у вас есть функция Foo, которая будет:

  • Создать и сгенерировать новый класс
  • Переназначить существующий класс на новый класс

Так почему бы просто не изменить существующий класс на нужный вам класс?

Тем не менее, вы можете сделать Foo статическим и взять "взять this вручную":

void Foo(TestClass*& this)
{
    delete this;
    this = // ...
}

Но это так же противно, как и другие ваши решения. Возможно, нам нужно больше контекста, чтобы дать вам лучшее решение.

0 голосов
/ 12 января 2010

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

...