Сбой указателя на указатель в случае, если указатель не - PullRequest
6 голосов
/ 17 декабря 2010

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

int main()
{
  // Pointer to a Pointer, current crash.
  InterfaceClass** ptrptr;
  ConcreteTwo* object = new ConcreteTwo();
  ptrptr = (InterfaceClass**)(&object); // cast is required for some reason.
  delete *ptrptr; // Crash here.

  // Single pointer, works fine.
  InterfaceClass* ptrptr;
  ConcreteTwo* object = new ConcreteTwo();
  ptrptr = object;
  delete ptrptr;

  // There are other cases where there are only 3 classes in the hierarchy.
  // This also works fine.
  InterfaceClass** ptrptr;
  ConcreteOne* object = new ConcreteOne();
  ptrptr = (InterfaceClass**)(&object);
  delete *ptrptr;

  return 0;
}

Иерархия классов выглядит следующим образом.Базовый класс представляет собой интерфейс с некоторыми чисто виртуальными функциями и включен многими классами по всей программе таким образом, что многие объекты потенциально наследуют его из более чем одного места.Из-за этого конкретная реализация должна расширить его с помощью «public virtual InterfaceClass».В этом примере удаление «виртуального» устраняет сбой.

class InterfaceClass {
public:
    virtual ~InterfaceClass() {};
    InterfaceClass() {}
};

class ConcreteClass : public virtual InterfaceClass {
public:
  ConcreteClass() { }
  virtual ~ConcreteClass() {}
};

class ConcreteOne : public ConcreteClass
{
public:
  ConcreteOne(void) {}
  virtual ~ConcreteOne(void) {}
};

class ConcreteTwo : public ConcreteOne
{
public:
  ConcreteTwo(void) {}
  virtual ~ConcreteTwo(void) {}
};

Ответы [ 4 ]

5 голосов
/ 17 декабря 2010

Итак, вам знаком тот факт, что тип указателя вряд ли имеет какое-либо отношение к типу, на который он указывает?Другими словами, где у вас сложилось впечатление, что если T1 наследуется от T2, то T1 * также наследуется от T2 *?Это было бы ошибочно.Теперь, как это применимо к вашей текущей ситуации?

  InterfaceClass** ptrptr;
  ConcreteTwo* object = new ConcreteTwo();
  ptrptr = (InterfaceClass**)(&object); // cast is required for some reason.

Вот основная проблема с приведением стиля C.Итак, это экономит некоторое горизонтальное пространство, но знаете ли вы, какой актерский состав вы только что сделали?Это не то, что вы думаете.Вы фактически выполнили reintpret_cast от типа ConcreteTwo * до несвязанного типа InterfaceClass *!Теперь адрес указателя не имеет ничего общего с типом, который вы называете.

Затем вы переводите интерпретированный тип указателя в delete, что быстро привело к нарушению вашего собственного сфинктера.

3 голосов
/ 17 декабря 2010

Ну, компилятор предупредил вас, вы решили сделать это по-своему ...

Вы не можете сделать это:

ptrptr = (InterfaceClass**)(&object);

потому что object указывает на ConcreteTwo, что не то же самое, что InterfaceClass. Подобъект InterfaceClass объекта ConcreteTwo расположен по другому адресу. *ptrptr не является указателем на экземпляр InterfaceClass.

Указатель, который вы передаете на delete, является указателем на ConcreteTwo, однако вы сказали компилятору, что это указатель на InterfaceClass. delete предполагает, что это действительно InterfaceClass, следовательно, крах.

1 голос
/ 17 декабря 2010

Я думаю, что проблема в линиях броска.Кстати, если вы удалите приведенный вами актерский состав, компилятор точно скажет вам, в чем проблема.

Если вы действительно хотите сделать это, и я настоятельно рекомендую вам сначала создать временный код:

ConcreteTwo* object = new ConcreteTwo();
InterfaceClass* ptr = object;

тогда вы можете взять его адрес и присвоить его переменной ptrptr:

InterfaceClass** ptrptr = &ptr;

теперь вы можете безопасно удалить его:

delete *ptrptr;

Учитыватьчто если ptr выйдет из области видимости до ptrptr, удаление, вероятно, снова завершится сбоем.

В остальном Ной объясняет, почему ваш код не работает.

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