SIGSEGV при изучении boost::multi_index
-
11-12-2019 - |
Вопрос
Я рвал на себе волосы, чтобы разобраться в этой ошибке, и решил попросить помощи.
у меня есть boost::multi_index
контейнер, в котором находится (string, string, double)
и в какой-то момент происходит сегфолт.
Вот упрощенная версия моего кода:
#include<iostream>
....
// mySet is a multi_index container which contains <(string str1), (string str2), (double val)>
typedef mySet::index<str1>::type set_by_str1;
...
for(unsigned int i=0; i < token.size(); ++i)
{
set_by_str1::iteration it = myContainer.get<str1>().find(token[i]);
while(it->str1() == token[i])
{
cout << it->str1() << ", " << it->str2() << ", " << it->val << endl;
}
*it++;
}
Кажется, что этот код работает довольно хорошо, но он дает сбой только тогда, когда он достигает определенного токена. (Напротив, он никогда не выходит из строя, когда он не соответствует токену).
Я думаю, это происходит потому, что it
выходит за пределы диапазона самого контейнера, но не понимаю, как это могло произойти.
Отображается сообщение об ошибке GDB:
Program received signal SIGSEGV, Segmentation fault.
0x08052e83 in std::string::size (this=0x806e190) at /usr/include/c++/4.4/bits/basic_string.h:629
629 { return _M_rep()->_M_length; }
(gdb) bactrace full
#0 0x08052e83 in std::string::size (this=0x806e190) at /usr/include/c++/4.4/bits/basic_string.h:629
No locals.
#1 0x08050475 in std::operator<< <char, std::char_traits<char>, std::allocator<char> > (__os=..., __str=...)
at /usr/include/c++/4.4/bits/basic_string.h:2503
No locals.
#2 0x0804e4e0 in MyClass:MyFunction (this=0xbffff534) at src/MyCode.cpp:353 (This is where while condition exists)
... dump of HUGE trace for multi_index ...
и он, очевидно, вылетает, когда я звоню it->str1()
в условии while, а не из-за вектора токена.Как я могу предотвратить это?Я попытался добавить if(it == myContainer.get<str1>().end()) break;
прямо внизу *it++
, но не помогло.
Кто-нибудь даст мне какую-нибудь подсказку?
Спасибо!
Решение
В вашем коде есть ряд проблем:
- Он выйдет из строя, если в контейнере нет элемента, эквивалентного
token[i]
, с того времениfind
возвращаетend()
, который не подлежит разыменованию. - В течение
while
петляit
может достичь конца контейнера, и вы снова не сможете его соблюдать. find
не даст вам первый элемент с ключом, эквивалентнымtoken[i]
, что, по-видимому, и есть то, что вам нужно;использоватьlower_bound
вместо.
Я предлагаю вам изменить код следующим образом:
pair<set_by_str1::iterator, set_by_str1::iterator> p =
myContainer.get<str1>().equal_range(token[i]);
while(p.first!=p.second)
{
cout << p.first->str1() << ", " << p.first->str2() << ", "
<< p.first->val << endl;
++(p.first);
}
Другие советы
Или it->str1()
является нулевым или token[i]
нулевой.
Убедитесь, что они не равны нулю, и ошибка сегментации исчезнет.
Возможно, вы захотите заменить while
с if
, также имейте в виду, что если find - это алгоритмы поиска из здесь, если элемент не найден, он возвращает итератор как итератор последнего элемента, который может иметь str1
как ноль.
Кроме того, вы уверены, что хотите выполнить итератор по символу строки токена и печатать каждое совпадение для каждого символа токена, а не просто печатать одно совпадение для всей строки токена? (по крайней мере, я думаю, что это строка, поскольку ваш пример кода этого не делает) я это не определяю).