Что может означать эта любопытная комбинация «while» и «delete»? - PullRequest
4 голосов
/ 22 декабря 2009

Просматривая довольно старый проект, я обнаружил следующий фрагмент любопытного кода (извлечен только соответствующий код):

class CCuriousClass {
    ~CCuriousClass();
    CSomeType* object;
};

CCuriousClass::~CCuriousClass()
{
    while( object != NULL ) {
        delete object;
    }
}

Наблюдал ли я за чем-либо или это простой путь к неопределенному поведению?

То, что я вижу здесь, это то, что если object является нулевым указателем в точке вызова CCuriousClass::~CCuriousClass(), все будет хорошо - никаких действий не предпринимается - но если object не равно нулю, это будет бесконечный цикл с неопределенное поведение внутри.

Это скорее всего ошибка или какая-то умная конструкция, которую я не понимаю?

Ответы [ 11 ]

13 голосов
/ 22 декабря 2009

Это похоже на ошибку.

9 голосов
/ 22 декабря 2009

Может быть, какой-то сумасшедший реализовал CSomeType с обратной ссылкой на свой CCuriousClass, и его деструктор иногда создает замену. Примерно так:

class CSomeType
{
public:
    explicit CSomeType(CCuriousClass &parent) : parent(parent) {}
    ~CSomeType()
    {
        parent.object = respawn() ? new CSomeType(parent) : 0;
    }
private:
    CCuriousClass &parent;
};

Я не предлагаю, чтобы кто-либо когда-либо писал такую ​​искаженную логику. Это, вероятно, все еще дает неопределенное поведение, так как я считаю, delete разрешено изменять указатель. Но это может объяснить, почему кто-то может подумать, что данный код может быть действительным.

С другой стороны, это, вероятно, просто ошибка, вызванная неправильным пониманием того, как delete работает.

6 голосов
/ 22 декабря 2009

Поскольку ваш вопрос, по-видимому, подразумевает "Что мог кто-то иметь в виду?" а не "Почему это фантастическая идея?" Я предлагаю следующее:

class CSomeType {
    CCuriousClass* m_plistentry;
    CSomeType* m_pnext;

    ~CSomeType() {
        m_plistentry->object = m_pnext;
    }
};

Основная идея могла состоять в том, что владелец указывает на заголовок списка, а список можно удалить только в заголовке. Если заголовок удаляется, он устанавливает свой родительский указатель на новый заголовок списка. Если родитель уничтожен, он уничтожает каждый элемент списка.

Теперь это явно код из сумасшедшего города.

3 голосов
/ 22 декабря 2009

Как вы говорите, это ошибка. delete не устанавливает указатель, который удаляет, в NULL, так что у вас есть бесконечный цикл, который может завершаться или не прерываться неопределенным поведением, которое вы получаете, удаляя один и тот же указатель дважды.

2 голосов
/ 24 декабря 2009

Еще одна возможная теория заключается в том, что с препроцессором кто-то сыграл противную шутку. Скажи:

struct delete_and_null {
    template<class T>
    delete_and_null& operator, (T*& p) {
      delete p;
      p = 0;
      return *this;
    }
} delete_and_null;

#define delete delete_and_null,

Это не объясняет необходимости в цикле, но, по крайней мере, это позволит избежать U.B. и прекратить в конце концов.

2 голосов
/ 22 декабря 2009

Такое поведение возможно при условии, что экземпляр CSomeType знает адрес, на котором хранится указатель на себя (элемент CSomeType ** в CSomeType), чтобы он мог сбросить его при удалении. Я понятия не имею, зачем это нужно.

пример:

struct self_know{
    self_know** pptr;
    int cnt;

    static self_know* create(self_know **_pptr){
        *_pptr = ::new self_know;
        (*_pptr)->cnt = 10;
        (*_pptr)->pptr = _pptr;
        return *_pptr;
    }

    void operator delete(void*it){
       self_know *s = (self_know*)it;
       if(--s->cnt<0){
         *(s->pptr)=0;
         ::delete s;
       }

    }
};

#include<iostream>
main(){
  self_know *p = 0;
  self_know::create(&p);
  while( p != 0){
     std::cout << p->cnt << std::endl;
     delete p;
  }
}
1 голос
/ 24 декабря 2009

Проверьте определение класса CSomeType. Может быть перегружена функция "! =". В противном случае это явно ошибка.

1 голос
/ 22 декабря 2009

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

CCuriousClass::~CCuriousClass()
{    
    delete object;    
}

или, что еще лучше, используйте умный указатель и избавьтесь от деструктора.

1 голос
/ 22 декабря 2009

Это похоже на ошибку, если деструктор CSomeType не может каким-либо образом изменить этот объект.

0 голосов
/ 25 июня 2010

Я подозреваю, что это от сумасшедшего программиста на Си, который не понимает деструкторы и / или операторы удаления. Или это, или кто-то, кто неуклюже набрал «время» вместо слова «если» и не знал, что удаление уже проверяет на ноль.

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

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