my_list.push_back()时分配错误

时间:2016-06-30 06:53:20

标签: c++ c++11 stdmap stdlist

我正在尝试控制正在开发的程序的工作流程。为此,我有一个map< unsigned int, list < unsigned int > >,其中第一个键将是id,第二个键(列表)将用于了解我是否正确结束所有任务。我在此列表中使用的唯一操作是:

myMap[iD].size()
myMap[iD].push_back(foo) <- ( foo is an unsigned int )
for (std::list<unsigned int>::iterator it=myMap[iD].begin(); it != myMap[iD].end(); ++it){
myMap[iD].erase(it)
}

我的地图长度可以增长到1452个元素,每个元素列表大小可以从1000到5000的数量级。

当我运行程序时,有时会收到分段错误,有时会出现错误的分配错误。我的猜测是,这来自push_back,因为:

  • 如果我不推回任何元素,程序运行正常。
  • 使用容器的分配器分配新元素的存储,这可能会在失败时抛出异常(对于默认分配器,如果分配请求不成功则抛出bad_alloc)。 http://www.cplusplus.com/reference/list/list/push_back/

这是我使用地图的代码的唯一部分:

if (FOO != 0){
    if (PID != 0){

        if ( myMap.size() + 5 < myMap.max_size()){
            if (myMap[PID].size() > 1000) myMap[PID].pop_front();
            myMap[PID].push_back(EVENTVALUE);
        }

    }
} else {
    if (PID != 0 and foo2 != 0 and myMap.find(PID) != myMap.end()) {
        for (std::list<unsigned int>::iterator it=myMap[PID].begin(); it != myMap[PID].end(); ++it){
            if (*it == foo2){
                cout << " erasing pid: " << PID <<  endl;
                myMap[PID].erase(it);
                if ( myMap[PID].size() == 0 ) myMap.erase(PID);
                break;
            }

        }
    }
}

我也尝试使用Valgrind工具,这是输出:

==4092== Invalid read of size 8
==4092==    at 0x4F09EB8: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib64/libstdc++.so.6.0.21)
==4092==    by 0x40CCA9: construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (new_allocator.h:120)
==4092==    by 0x40CCA9: _S_construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (alloc_traits.h:254)
==4092==    by 0x40CCA9: construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (alloc_traits.h:393)
==4092==    by 0x40CCA9: std::vector<std::string, std::allocator<std::string> >::push_back(std::string const&) (stl_vector.h:905)
==4092==    by 0x4157AC: foo::foo(std::basic_ofstream<char, std::char_traits<char> >&) (foo.cc:1743)
==4092==    by 0x404F49: main (foo.cc:3159)
==4092==  Address 0x6157d08 is 0 bytes after a block of size 8 alloc'd
==4092==    at 0x4C29670: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==4092==    by 0x40DB77: allocate (new_allocator.h:104)
==4092==    by 0x40DB77: _M_allocate (stl_vector.h:168)
==4092==    by 0x40DB77: void std::vector<std::string, std::allocator<std::string> >::_M_emplace_back_aux<std::string>(std::string&&) (vector.tcc:404)
==4092==    by 0x408F3E: push_back (stl_vector.h:920)
==4092==    by 0x408F3E: split(std::string const&, char, int) (foo.cc:416)
==4092==    by 0x41577F: lustreLine::toPRV(std::basic_ofstream<char, std::char_traits<char> >&) (foo.cc:1741)
==4092==    by 0x404F49: main (foo.cc:3159)
==4092== 
==4092== Invalid read of size 4
==4092==    at 0x4F09EBB: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib64/libstdc++.so.6.0.21)
==4092==    by 0x40CCA9: construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (new_allocator.h:120)
==4092==    by 0x40CCA9: _S_construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (alloc_traits.h:254)
==4092==    by 0x40CCA9: construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (alloc_traits.h:393)
==4092==    by 0x40CCA9: std::vector<std::string, std::allocator<std::string> >::push_back(std::string const&) (stl_vector.h:905)
==4092==    by 0x4157AC: foo::foo(std::basic_ofstream<char, std::char_traits<char> >&) (foo.cc:1743)
==4092==    by 0x404F49: main (foo.cc:3159)
==4092==  Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd
==4092== 
==4092== 
==4092== Process terminating with default action of signal 11 (SIGSEGV)
==4092==  Access not within mapped region at address 0xFFFFFFFFFFFFFFF8
==4092==    at 0x4F09EBB: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib64/libstdc++.so.6.0.21)
==4092==    by 0x40CCA9: construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (new_allocator.h:120)
==4092==    by 0x40CCA9: _S_construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (alloc_traits.h:254)
==4092==    by 0x40CCA9: construct<std::basic_string<char>, const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&> (alloc_traits.h:393)
==4092==    by 0x40CCA9: std::vector<std::string, std::allocator<std::string> >::push_back(std::string const&) (stl_vector.h:905)
==4092==    by 0x4157AC: foo::foo(std::basic_ofstream<char, std::char_traits<char> >&) (fpp.cc:1743)
==4092==    by 0x404F49: main (foo.cc:3159)
==4092==  If you believe this happened as a result of a stack
==4092==  overflow in your program's main thread (unlikely but
==4092==  possible), you can try to increase the size of the
==4092==  main thread stack using the --main-stacksize= flag.
==4092==  The main thread stack size used in this run was 8388608.

[...]

(如果需要更多输出,请询问)

我不得不为隐私更改一些变量名称,希望这不是问题。

感谢您阅读并度过美好的一天!

1 个答案:

答案 0 :(得分:7)

第一个for循环错误:

for (std::list<unsigned int>::iterator it=myMap[iD].begin(); it != myMap[iD].end(); ++it){
    myMap[iD].erase(it);
}

因为每次调用erase后迭代器it都会失效。

您可以将其重写为:

for (auto it = myMap[iD].begin(); it != myMap[iD].end(); )
{
    it = myMap[iD].erase(it);
}

或者更好,只是

myMap[iD].clear();

在你的问题中似乎还有其他for循环,你犯了类似的错误 - 通常你需要使用这种模式:

for (auto it = foo.begin(); it != foo.end(); )
{
    if (some_condition)
        it = foo.erase(it);   // erase map entry, update iterator
    else
        ++it;                 // bump iterator
}

请参阅cppreference.com entry for std::map::erase上的示例。