URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 6380
[ Назад ]

Исходное сообщение
"list::clear() и list::assign() почему-то портят vector"

Отправлено TaL , 17-Апр-07 00:22 
Возможно я что-то глупое спрошу, но я уже второй день бьюсь и в инете нигде по сути ответа не могу найти, а сроки поджимают. Ситуация такая: есть код, в котором я создаю массив контейнеров std::list и контейнер std::vector:

struct Addresses
{
    unsigned short doc;
    unsigned short line;
    short word;
    //unsigned int key;
    void operator=(Addresses a);
    Addresses();
    int    Read(int &fileid, const int offset);
};

struct united_list
{
    Addresses addr;
    int* keys;
    united_list()
    {
        keys=NULL;
    };
    ~united_list()
    {
        if(keys)
            delete[] keys;
        keys=NULL;
    };
};

typedef   list<united_list> addList;

struct TMatch
{
    int addr_size;
    Addresses* addr;
    int key_size;
    int* keys;

    TMatch();
    TMatch(int ad_size, int ky_size);
    ~TMatch();

    void operator=(TMatch a);
    void Init(int ad_size, int ky_size);
    void clear();
};

addList* bigquery;
vector<TMatch*> result;

Затем происходят вызовы функций таким вот образом:

int Intersect(const int offNum,Dist* &dist,addList* &adds,vector<TMatch*>& result);

в ней вызывается функция

void IntersectPair(const int i,Dist* &dist,addList* &adds);

в обеих, обратите внимание, третий параметр - ссылка на созданый выше bigquery, result - он везде тот же result. Однако IntersectPair объекта result вообще не касается, при этом когда я после операций в IntersectPair пытаюсь сделать result.reserve(xxx); он пишет про ошибку glibc про corrupt list. Закоментировав вызов IntersectPair, ошибка исчезает, однако, естественно код работает неправильно.

Возможно следующее подскажет, в чем может быть проблема. В том же месте кода я сделал такую вот трассировку:

for(i=0;i<__size;i++)
    {
        resultSet=new TMatch(offNum,__sorter.key_sort_num);
        resultSet->addr[offNum-1]=adds_i_current_iterator->addr;
        result.push_back(resultSet);
        if(!i)
        {
            cout<<resultSet->addr[0].doc<<"."<<resultSet->addr[0].line<<"."<<resultSet->addr[0].word<<endl;
            cout<<adds_i_current_iterator->addr.doc<<"."<<adds_i_current_iterator->addr.line<<"."<<adds_i_current_iterator->addr.word<<endl;
            cout<<result[0][0].addr[0].doc<<"."<<result[0][0].addr[0].line<<"."<<result[0][0].addr[0].word<<endl;
        }
        adds_i_current_iterator++;
    }
    cout<<result[0][0].addr[0].doc<<"."<<result[0][0].addr[0].line<<"."<<result[0][0].addr[0].word<<endl;
    adds[offNum-1].clear();
    cout<<result[0][0].addr[0].doc<<"."<<result[0][0].addr[0].line<<"."<<result[0][0].addr[0].word<<endl;

а выдал он мне такую вот фишку:

1.2.2
1.2.2
1.2.2
1.2.2
6587.230.0

Опять же, за коментировав
adds[offNum-1].clear()
вывод становится нормальным

1.2.2
1.2.2
1.2.2
1.2.2
1.2.2

Кстати, в обоих случаях последующие элементы вектора results не страдают и нормально обрабатываются.

ну то есть получается, что после вызова adds[offNum-1].clear(); у меня портится содержимое вектора result, хотя везде происходит присваивание по значениям, то есть создается где нужно новый обхъект, аллоцируется оператором new память и туда в нужные места заливаются значения соответственные.

Помогите, пожалуйста, я ума не приложу, как у меня могут так хитро переплестись контейнеры. Скажите, если нужно дополнительно код выложить. Заранее спасибо.


Содержание

Сообщения в этом обсуждении
"list::clear() и list::assign() почему-то портят vector"
Отправлено dronord , 17-Апр-07 09:35 
Странно вот это
adds[offNum-1].clear();

Проследите за offNum, он правда везде >0 ?

"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 11:35 
>Странно вот это
adds[offNum-1].clear();

>Проследите за offNum, он правда везде >0 ?

Абсолютно точно offNum>=1.



"list::clear() и list::assign() почему-то портят vector"
Отправлено dronord , 17-Апр-07 11:59 
Сделайте у united_list копирующий конструктор, потому что у Вас
typedef   list<united_list> addList;
и в нем есть указатель int*.

Ещё бы я сделал аргумент оператора присвоения у первой структуры передаваемым по ссылке или указателю.


"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 12:41 
>Сделайте у united_list копирующий конструктор, потому что у Вас
typedef   list<united_list> addList;
и в нем есть указатель int*.

>
>Ещё бы я сделал аргумент оператора присвоения у первой структуры передаваемым по
>ссылке или указателю.

Не совсем понял,копирующий конструктор Addresses(Addresses&)?

Относительно оператора присвоения, он у меня сейчас такой:

void Addresses::operator=(Addresses& a)
{
    doc=a.doc;
    line=a.line;
    word=a.word;
}

Этого недостаточно?



"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 12:45 
и еще, когда создается new TMatch(xxx) выполняется такой вот код

TMatch::TMatch(int ad_size, int ky_size)
{
    Init(ad_size,ky_size);
}

void TMatch::Init(int ad_size, int ky_size)
{
    addr_size=ad_size;
    addr=new Addresses[addr_size];
    key_size=ky_size;
    keys=new int[key_size];
}

Я правильно понимаю, что этого недостаточно и лучше вместо присваивания использовать копирующий конструктор?


"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 12:49 
Я идею не совсем понял идею копирующего конструктора для united_list, потому как bigquery нормально инициализируется и не портится в процессе выполнения, проблема в том, что изменения в bigquery уже после копирования информации в вектор result портят этот вектор...



"list::clear() и list::assign() почему-то портят vector"
Отправлено dronord , 17-Апр-07 13:10 
В list'е хранятся копии объектов, которые Вы туда положили.
Если не реализовать правильный копир. конструктор и возможно оператор присвоения для united_list, компилятор сам их сгенерит и сделает это неверно, потому что в классе имеется указатель int* united_list::keys.

Изменения Вашего обекта или объекта из list'а скажутся на объекте из list'а или Вашем, соответственно. Последствия предсказать не могу.


"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 15:26 
>В list'е хранятся копии объектов, которые Вы туда положили.
>Если не реализовать правильный копир. конструктор и возможно оператор присвоения для united_list,
>компилятор сам их сгенерит и сделает это неверно, потому что в
>классе имеется указатель int* united_list::keys.
>
>Изменения Вашего обекта или объекта из list'а скажутся на объекте из list'а
>или Вашем, соответственно. Последствия предсказать не могу.


Проверил аккуратно код, связанный с  int* united_list::keys  - коряво написано, но по существу все аллоцирование и присваивание производится мною явно.


"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 15:58 
Спасибо за ответ, dronord.Я видимо неточно поставил вопрос, я его переформулировал.

"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 15:30 
Я наверно, не на том заострил внимание в исходном посте. Суть проблемы вот какая:

main()
{
...
vector<TMatch*> result;
    int NumberOfResults=Intersect(Params.NumOfOffsets,Params.SearchDistances,bigquery,result);
...
}

где

int Intersect(const int offNum,Dist* &dist,addList* &adds,vector<TMatch*>& result)
{
   ..../*тут ничего не трогает result*/
   IntersectPair(i,dist,adds);
   Sweep(offNum,dist,adds,result);
   ..../*тут ничего не трогает result*/
}

где

void IntersectPair(const int i,Dist* &dist,addList* &adds)
{
(к result вообще доступа не должно быть)
}

void Sweep(const int offNum,Dist* &dist,addList* &adds,vector<TMatch*>& result)
{
        int __size=adds[offNum-1].size();
    cout<<__size<<"   "<<result.capacity()<<endl;
    result.reserve(__size);
    cout<<__size<<"   "<<result.capacity()<<endl;
   ...
}

то есть до места result.reserve(__size); !единственное! обращение к объекту result это его создание с помощью vector<TMatch*> result;

Но вот что пишет мне указанное место из кода Sweep:

18537   0
*** glibc detected *** corrupted double-linked list: 0x00002b8fc5f0e158 ***

Но ведь result - это vector. А если поврежден list adds (он же bigquery), то почему ошибка выводится при обращению к члену-функции vector::reserve(int)?


"list::clear() и list::assign() почему-то портят vector"
Отправлено dronord , 17-Апр-07 15:59 
Покажите backtrace.
Вообще, лист должен разваливаться. Почему? Я изложил и ещё раз повторюсь =). Указатель keys копии объекта в листе указывает туда же, куда и указатель исходного объекта. Следовательно, изменение одного из них затронет общую память - произойдет падение или все что угодно. В структуре united_list необходимы копир. конструктор и оператор присвоения, которые правильно обработают указатель.

"list::clear() и list::assign() почему-то портят vector"
Отправлено Arifolth , 17-Апр-07 16:00 
>Покажите backtrace.
>Вообще, лист должен разваливаться. Почему? Я изложил и ещё раз повторюсь =).
>Указатель keys копии объекта в листе указывает туда же, куда и
>указатель исходного объекта. Следовательно, изменение одного из них затронет общую память
>- произойдет падение или все что угодно. В структуре united_list необходимы
>копир. конструктор и оператор присвоения, которые правильно обработают указатель.


а чего valgrind хорошего говорит про ваше приложение?


"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 17:35 
>>Покажите backtrace.
>>Вообще, лист должен разваливаться. Почему? Я изложил и ещё раз повторюсь =).
>>Указатель keys копии объекта в листе указывает туда же, куда и
>>указатель исходного объекта. Следовательно, изменение одного из них затронет общую память
>>- произойдет падение или все что угодно. В структуре united_list необходимы
>>копир. конструктор и оператор присвоения, которые правильно обработают указатель.
>
>
>а чего valgrind хорошего говорит про ваше приложение?


а valgrind молчит, равно как и gdb, потому как их нету (вот такой вот сюрприз, мне тоже было приятно), а локально тестить систему невозможно...


"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 16:31 
>Покажите backtrace.
>Вообще, лист должен разваливаться. Почему? Я изложил и ещё раз повторюсь =).
>Указатель keys копии объекта в листе указывает туда же, куда и
>указатель исходного объекта. Следовательно, изменение одного из них затронет общую память
>- произойдет падение или все что угодно. В структуре united_list необходимы
>копир. конструктор и оператор присвоения, которые правильно обработают указатель.

Пункт 0. Я может быть туплю совсем, вы не могли бы в код united_list добавить то, что вы конкретно имеете в виду... копирующий что именно конструктор?

Пункт 1. Бог с ним с листом - он нормально работает :)
В копии листовой указаетль keys указывает на другое место, которое создается при заполнении
temp.keys=new int[num_keys];
                    for(l=0;l<num_keys;l++)
                    {
                        temp.keys[l]=ReadKey(Params.Offsets[i][j]+k,__sorter.sorters[key_ind[l]].keysort);
                    }
_iterator=adds[i].insert(_iterator,temp);

Я этот контейнер просто руками заполняю каждый отдельный. Вы это имели в виду?
Кроме того, на тех примерах, на которых я щас тестил я специально задавал условия, чтобы keys==NULL все время (а то и там бы наверно намучался бы).
Несчастье мое не в том что лист вредится или не туда указывает, а в том, что когда я его освобождать начинаю, портится vector, который я создаю независимо от этого листа...


"list::clear() и list::assign() почему-то портят vector"
Отправлено dronord , 17-Апр-07 16:52 
Синхронизируйте этот код со своим и ждем отчет =)
П.С. Код не компилировал, надеюсь смысел понятен.

class united_list
{
...

public:
int keys_size;
int *keys; // Для примера сделал открытым членом

/*
*  Копирующий конструктор
*/
united_list ( const united_list & obj )
{
    this->addr = obj.addr;
    this->keys = new int[ obj.keys_size ];
    for ( int i = 0; i < obj.keys_size; ++i)
    {
        this->keys[i] = obj.keys[i];
    }
}

/*
*  Оператор присвоения
*/
united_list &operator=(const united_list &obj )
{
    this->addr = obj.addr;
    delete [] this->keys; // Прежние значения боле не нужны
    this->keys = new int[ obj.keys_size ];
    for ( int i = 0; i < obj.keys_size; ++i)
    {
        this->keys[i] = obj.keys[i];
    }
    return *this;
}

};


"list::clear() и list::assign() почему-то портят vector"
Отправлено TaL , 17-Апр-07 17:33 
Мусчина, вы волшебник!!
Я не понял, на какое именно место повлияло, результат сирано неправильный - видимо дальше уже алгоритмическая обшибка, но теперь хотя бы не вылетает...

Поделитесь секретом, какое место я не дочитал? Ну то есть, что я сделал только что?%)


"list::clear() и list::assign() почему-то портят vector"
Отправлено dronord , 17-Апр-07 18:18 
Это из собственного опыта. Потом уж не помню, нашел у Страуструпа или нет.
Какой метод из двух нужен, зависит, наверное, от компилятора. У меня (gcc 3.4.6) было достаточно копирующего конструктора.