Возможно я что-то глупое спрошу, но я уже второй день бьюсь и в инете нигде по сути ответа не могу найти, а сроки поджимают. Ситуация такая: есть код, в котором я создаю массив контейнеров 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 память и туда в нужные места заливаются значения соответственные.
Помогите, пожалуйста, я ума не приложу, как у меня могут так хитро переплестись контейнеры. Скажите, если нужно дополнительно код выложить. Заранее спасибо.
Странно вот этоadds[offNum-1].clear();
Проследите за offNum, он правда везде >0 ?
>Странно вот этоadds[offNum-1].clear();
>Проследите за offNum, он правда везде >0 ?Абсолютно точно offNum>=1.
Сделайте у united_list копирующий конструктор, потому что у Васtypedef list<united_list> addList;и в нем есть указатель int*.Ещё бы я сделал аргумент оператора присвоения у первой структуры передаваемым по ссылке или указателю.
>Сделайте у united_list копирующий конструктор, потому что у Васtypedef list<united_list> addList;и в нем есть указатель int*.
>
>Ещё бы я сделал аргумент оператора присвоения у первой структуры передаваемым по
>ссылке или указателю.Не совсем понял,копирующий конструктор Addresses(Addresses&)?
Относительно оператора присвоения, он у меня сейчас такой:
void Addresses::operator=(Addresses& a)
{
doc=a.doc;
line=a.line;
word=a.word;
}Этого недостаточно?
и еще, когда создается 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];
}Я правильно понимаю, что этого недостаточно и лучше вместо присваивания использовать копирующий конструктор?
Я идею не совсем понял идею копирующего конструктора для united_list, потому как bigquery нормально инициализируется и не портится в процессе выполнения, проблема в том, что изменения в bigquery уже после копирования информации в вектор result портят этот вектор...
В list'е хранятся копии объектов, которые Вы туда положили.
Если не реализовать правильный копир. конструктор и возможно оператор присвоения для united_list, компилятор сам их сгенерит и сделает это неверно, потому что в классе имеется указатель int* united_list::keys.Изменения Вашего обекта или объекта из list'а скажутся на объекте из list'а или Вашем, соответственно. Последствия предсказать не могу.
>В list'е хранятся копии объектов, которые Вы туда положили.
>Если не реализовать правильный копир. конструктор и возможно оператор присвоения для united_list,
>компилятор сам их сгенерит и сделает это неверно, потому что в
>классе имеется указатель int* united_list::keys.
>
>Изменения Вашего обекта или объекта из list'а скажутся на объекте из list'а
>или Вашем, соответственно. Последствия предсказать не могу.
Проверил аккуратно код, связанный с int* united_list::keys - коряво написано, но по существу все аллоцирование и присваивание производится мною явно.
Спасибо за ответ, dronord.Я видимо неточно поставил вопрос, я его переформулировал.
Я наверно, не на том заострил внимание в исходном посте. Суть проблемы вот какая: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)?
Покажите backtrace.
Вообще, лист должен разваливаться. Почему? Я изложил и ещё раз повторюсь =). Указатель keys копии объекта в листе указывает туда же, куда и указатель исходного объекта. Следовательно, изменение одного из них затронет общую память - произойдет падение или все что угодно. В структуре united_list необходимы копир. конструктор и оператор присвоения, которые правильно обработают указатель.
>Покажите backtrace.
>Вообще, лист должен разваливаться. Почему? Я изложил и ещё раз повторюсь =).
>Указатель keys копии объекта в листе указывает туда же, куда и
>указатель исходного объекта. Следовательно, изменение одного из них затронет общую память
>- произойдет падение или все что угодно. В структуре united_list необходимы
>копир. конструктор и оператор присвоения, которые правильно обработают указатель.
а чего valgrind хорошего говорит про ваше приложение?
>>Покажите backtrace.
>>Вообще, лист должен разваливаться. Почему? Я изложил и ещё раз повторюсь =).
>>Указатель keys копии объекта в листе указывает туда же, куда и
>>указатель исходного объекта. Следовательно, изменение одного из них затронет общую память
>>- произойдет падение или все что угодно. В структуре united_list необходимы
>>копир. конструктор и оператор присвоения, которые правильно обработают указатель.
>
>
>а чего valgrind хорошего говорит про ваше приложение?
а valgrind молчит, равно как и gdb, потому как их нету (вот такой вот сюрприз, мне тоже было приятно), а локально тестить систему невозможно...
>Покажите 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, который я создаю независимо от этого листа...
Синхронизируйте этот код со своим и ждем отчет =)
П.С. Код не компилировал, надеюсь смысел понятен.
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;
}};
Мусчина, вы волшебник!!
Я не понял, на какое именно место повлияло, результат сирано неправильный - видимо дальше уже алгоритмическая обшибка, но теперь хотя бы не вылетает...Поделитесь секретом, какое место я не дочитал? Ну то есть, что я сделал только что?%)
Это из собственного опыта. Потом уж не помню, нашел у Страуструпа или нет.
Какой метод из двух нужен, зависит, наверное, от компилятора. У меня (gcc 3.4.6) было достаточно копирующего конструктора.