Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [STL] list. Освобождение элемента. 
:(
    Опции темы
gleb1310
Дата 1.7.2010, 10:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 1.7.2010

Репутация: нет
Всего: нет



Здравствуйте, знатоки.
Писал приложение, активно использующее указатели. Чтобы облегчить себе работу по освобождению памяти, решил заодно в программу сборщик мусора включить. Посмотрел книжки по этому делу. Выбрал алгоритм (подсчет ссылок). Попробовал реализовать. Реализация падала при очистке памяти. Решил содрать код из книжки. ТО ЖЕ САМОЕ!!!!!! и в том же месте.
Вот код сборки мусора, из книжки:
Код

template <class T,int size> bool GCPtr<T,size>::collect()
{
    bool memfreed=false;
    list<GCInfo<T>>::iterator p;
    do
    {
        for(p=gclist.begin();p!=gclist.end();p++)
        {
            if(p->refcount>0) continue;
            memfreed=true;
            gclist.remove(*p); //<==Вот после этого p->memPtr становится равным 0xfeeefeee
            if(p->memPtr) //Здесь программа естественно падает при попытке обращения к такому 
                                              //адресу "list iterator not deferensable"
            {
                if(p->isArray) delete[] p->memPtr;
                else    delete p->memPtr;
            }
            
            break;
        }
    }while(p!=gclist.end());
    return memfreed;
}

Попробовал выяснить, откуда такое значение берется. Насколько я разобрался, функция void remove(const _Ty& _Val_arg) из list вызывает функцию iterator erase(const_iterator _Where) оттуда же вот так:
Код

  _First = erase(_First);


И здесь возвращается значение memPtr=0xfeefee вот отсюда:
Код

    iterator erase(const_iterator _Where)
//....................пропущено несколько строк
        if (_Pnode != _Myhead)
            {    // not list head, safe to erase
            _Nextnode(_Prevnode(_Pnode)) = _Nextnode(_Pnode);
            _Prevnode(_Nextnode(_Pnode)) = _Prevnode(_Pnode);
            this->_Alnod.destroy(_Pnode);
            this->_Alnod.deallocate(_Pnode, 1);//<==ВОТ ОТСЮДА
            --_Mysize;
            }
        return (_Make_iter(_Where));
        }

В общем вопросов много: что значит такое значение указателя? почему оно возникает? как с этим бороться? как это обойти в данной ситуации?
Помогите советом. Заранее спасибо.
ps только не надо спрашивать ЗАЧЕМ

Это сообщение отредактировал(а) gleb1310 - 1.7.2010, 10:46
PM MAIL   Вверх
azesmcar
Дата 1.7.2010, 10:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Во первых приведи код в порядок и используй тэг "Код", а так код читать никто не будет, во вторых все уже давно реализовано, зачем изобретать велосипед?
PM   Вверх
xvr
Дата 1.7.2010, 12:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(gleb1310 @  1.7.2010,  10:18 Найти цитируемый пост)
Попробовал выяснить, откуда такое значение берется.
И так понятно откуда - как попросили уделить элемент из списка (gclist.remove(*p);), так список его и удалил. Попутно разрушил и содержимое элемента (позвал ему деструктор и вернул память в кучу). Так что делать p->memPtr ПОСЛЕ gclist.remove явно незаконно


PM MAIL   Вверх
Earnest
Дата 1.7.2010, 13:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



gleb1310, особо не вникала, но вроде бы так: ты удаляешь элемент списка, и итератор становится невалидным, а потом пытаешься им же воспользоваться. Поменяй местами remove и  скобку if(p->memPtr).
И еще, нафига удалять из списка значение, если у тебя есть итератор? Можно сразу писать erase. 
И можно написать все в рамках простого цикла, без выкрутасов:
Код

for (iterator p = list.begin(); p != list.end(); )   // внимание - нет инкремента!
{
   if (трам-пам-пам)
   {
      ...
      p = list.erase (p);     // получаем след. итератор
   }
   else ++p;                   // иначе инкремент
}

А 0xfeeefeee -это вариант "дохлой коровы" от Майкрософт - так они в дебаге освобожденные указатели помечают.
А в некоторых других компиляторах это действительно deedbeef


--------------------
...
PM   Вверх
gleb1310
Дата 1.7.2010, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 1.7.2010

Репутация: нет
Всего: нет



Цитата

Поменяй местами remove и  скобку if(p->memPtr)

там дальше тоже используется p->memPtr. не получится.
Дело в том, что это код из книги Герберта Шилдта "Искусство программирования на С++". В вопросе я конечно не весь код написал. вроде бы в нем все должно быть правильно. Но он не работает. Вот я и хочу понять почему.
PM MAIL   Вверх
Earnest
Дата 1.7.2010, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(gleb1310 @  1.7.2010,  15:11 Найти цитируемый пост)
Вот я и хочу понять почему

Тебе же сказали - потому что код неправильный. Что, у Шилдта действительно stl::list использовался, или это ты "творчески переосмыслил"? Или, может, ты думаешь, что в книгах косяков не бывает?


--------------------
...
PM   Вверх
gleb1310
Дата 1.7.2010, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 1.7.2010

Репутация: нет
Всего: нет



Цитата

Что, у Шилдта действительно stl::list использовался, или это ты "творчески переосмыслил"?

Да, использовался. Именно так все и реализовано у него.
Его сборщик состоит из шаблонного класса GCPtr - указатель, предназначенный для сбора мусора, поддерживающий список, который связывает счетчик ссылок с каждым фрагментом памяти, выделенным с помощью GCPtr; класса GCInfo - элементы списка из класса GCPtr; Iter - шаблонный класс (== iterator из STL + контроль границ).

PM MAIL   Вверх
gleb1310
Дата 1.7.2010, 15:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 1.7.2010

Репутация: нет
Всего: нет



Может быть я задаю глупые вопросы, но все же:
из списка gclist удаляются элементы значения которых равняется значению того, на что указывает p?

PM MAIL   Вверх
xvr
Дата 1.7.2010, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(gleb1310 @  1.7.2010,  15:43 Найти цитируемый пост)
из списка gclist удаляются элементы значения которых равняется значению того, на что указывает p?
Да. И в первую очередь - сам p

PM MAIL   Вверх
gleb1310
Дата 1.7.2010, 18:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 1.7.2010

Репутация: нет
Всего: нет



Цитата

Да. И в первую очередь - сам p

Что это значит? а если элемент не последний? Если удалить сам итератор, то как перейти на следующий элемент? 
PM MAIL   Вверх
xvr
Дата 1.7.2010, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(gleb1310 @  1.7.2010,  18:49 Найти цитируемый пост)
Если удалить сам итератор, то как перейти на следующий элемент?
Замечательный вопрос! А сами как думаете?  smile 

PM MAIL   Вверх
Earnest
Дата 2.7.2010, 07:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(gleb1310 @  1.7.2010,  19:49 Найти цитируемый пост)

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

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


--------------------
...
PM   Вверх
gleb1310
Дата 3.7.2010, 06:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 1.7.2010

Репутация: нет
Всего: нет



Посмотрите пожалуйста код, может что неправильно:
Код

template <class T,int size> bool GCPtr<T,size>::collect()
{
    bool memfreed=false;
    list<GCInfo<T>>::iterator p;
    T *tmp_memPtr;
    bool tmp_isArray;
    unsigned tmp_arraySize;
    for(p=gclist.begin();p!=gclist.end();)
    {
        if(p->refcount>0)
        {++p; continue;}
        else
        {
            if(p->memPtr)
            {
                tmp_memPtr=p->memPtr;
                tmp_isArray=p->isArray;
                tmp_arraySize=p->arraySize;
            }
            memfreed=true;
            p=gclist.erase(p);
            if(tmp_memPtr)
            {
                if(tmp_isArray) delete[] tmp_memPtr;
                else delete tmp_memPtr;
                tmp_memPtr=NULL;
            }
                        
            }
    }
    return memfreed;
}
 
PM MAIL   Вверх
xvr
Дата 3.7.2010, 09:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Переменная tmp_memPtr не описана, да и вообще не нужна:
Код

            if(p->memPtr)
            {
                if (p->isArray) delete [] p->memPtr;
                else delete p->memPtr;
            }

PM MAIL   Вверх
gleb1310
Дата 3.7.2010, 12:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 1.7.2010

Репутация: нет
Всего: нет



xvr:
Цитата

Переменная tmp_memPtr не описана


Что значит не описана????
Код

T *tmp_memPtr;


xvr:
Цитата

да и вообще не нужна

В ТОМ ТО И ВОПРОС!!!!!!!! Без нее НИКАК память не очистить! Прочитайте первый пост. После удаления элемента из списка указатель p->memPtr становится равным 0xfeefee и обратиться по нему к занятой памяти НЕВОЗМОЖНО!
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1286 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.