2017-10-09 148 views
1

在一些代码,我有型PlayerObjectstd :: list :: sort与自定义比较器的分段错误?

std::list<PlayerObject> unknownPlayers; 

的对象链接列表,我需要根据某些属性的对象进行排序,所以我用类

class CountCmp 
    : public std::binary_function< PlayerObject, PlayerObject, bool > 
{ 
public: 
    result_type operator()(const first_argument_type & lhs, 
          const second_argument_type & rhs) const 
     { 
     return lhs.posCount() < rhs.posCount(); 
     } 
}; 

通过

unknownPlayers.sort(PlayerObject::CountCmp());

但由于某种原因程序正在接收SEGV。我用-fsanitize=address编译标志来研究和堆栈跟踪像:

ASAN:SIGSEGV 
================================================================= 
==8521==ERROR: AddressSanitizer: SEGV on unknown address 0x0003000003e8 (pc 0x7fe7ca6d6540 bp 0x7fff07c51720 sp 0x7fff07c516e8 T0) 
#0 0x7fe7ca6d653f in std::__detail::_List_node_base::_M_transfer(std::__detail::_List_node_base*, std::__detail::_List_node_base*) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x9e53f) 
#1 0x881e58 in std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::_M_transfer(std::_List_iterator<rcsc::PlayerObject>, std::_List_iterator<rcsc::PlayerObject>, std::_List_iterator<rcsc::PlayerObject>) /usr/include/c++/5/bits/stl_list.h:1747 
#2 0x87f79f in std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::splice(std::_List_const_iterator<rcsc::PlayerObject>, std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >&&, std::_List_const_iterator<rcsc::PlayerObject>) /usr/include/c++/5/bits/stl_list.h:1444 
#3 0x87d22e in std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::splice(std::_List_const_iterator<rcsc::PlayerObject>, std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >&, std::_List_const_iterator<rcsc::PlayerObject>) /usr/include/c++/5/bits/stl_list.h:1464 
#4 0x87d90c in void std::__cxx11::list<rcsc::PlayerObject, std::allocator<rcsc::PlayerObject> >::sort<rcsc::PlayerObject::CountCmp>(rcsc::PlayerObject::CountCmp) (/home/felipe_coimbra/.../sample_player+0x87d90c) 
#5 0x86c3e3 in rcsc::WorldModel::localizePlayers(rcsc::VisualSensor const&) /home/felipe_coimbra/.../world_model.cpp:2412 
#6 0x864b37 in rcsc::WorldModel::updateAfterSee(rcsc::VisualSensor const&, rcsc::BodySensor const&, rcsc::ActionEffector const&, rcsc::GameTime const&) /home/felipe_coimbra/.../world_model.cpp:910 
#7 0x81a7ac in rcsc::PlayerAgent::Impl::analyzeSee(char const*) /home/felipe_coimbra/.../player_agent.cpp:1552 
#8 0x819b52 in rcsc::PlayerAgent::parse(char const*) /home/felipe_coimbra/.../player_agent.cpp:1393 
#9 0x816519 in rcsc::PlayerAgent::handleMessage() /home/felipe_coimbra/.../player_agent.cpp:886 
#10 0x75b3a8 in rcsc::BasicClient::runOnline(rcsc::SoccerAgent*) /home/felipe_coimbra/.../basic_client.cpp:158 
#11 0x75ac9e in rcsc::BasicClient::run(rcsc::SoccerAgent*) /home/felipe_coimbra/.../basic_client.cpp:93 
#12 0x5e933e in main /home/felipe_coimbra/.../main_player.cpp:102 
#13 0x7fe7c9d6f82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) 
#14 0x5e8ed8 in _start (/home/felipe_coimbra/.../sample_player+0x5e8ed8) 

AddressSanitizer can not provide additional info. 
SUMMARY: AddressSanitizer: SEGV ??:0  std::__detail::_List_node_base::_M_transfer(std::__detail::_List_node_base*, std::__detail::_List_node_base*) 
==8521==ABORTING 

在我看来,比较好的是严格弱排序。那么在std :: list :: sort中会出现段错误的其他可能原因是什么?

编辑1:

我试着用list::iteratorlist::reverse_iterator只是排序前tranverse unknownPlayers并能正常工作。我甚至可以通过posCount()方法访问值,并且返回的值没有任何异常。

编辑2:

我一直在试图挑选相关的代码后,但我发现它有点麻烦。 我想unknownPlayers一些相关的事实是:

  1. 它是由std::list::splice方法填充:

    unknownPlayers.splice(unknownPlayers.end(), new_unknown_players);

new_unknown_players也被splice填补。基本上在每个游戏周期都有关于所看到的玩家的新信息,并且这些玩家可以被识别为队友,对手或者根本不识别(未知玩家)。尝试通过接近度阈值将未识别的玩家与先前识别的玩家(队友或对手)进行匹配,如果失败,则将他们拼接成new_unknown_players链接列表。

  • sort也不会崩溃以同样的方式,如果我尝试拼接的中的代码行上述

  • 但是该呼叫之前unknownPlayers排序,sort不会崩溃而unknownPlayers是空的(感谢上帝,它不是这样搞砸了),第一次splice实际上增加了新的对象,并使其第一次非空。

  • 也许这意味着在代码的其他部分有东西正在破坏列表?我仍然无法理解为什么转换可以。

    这部分代码的:

    ////////////////////////////////////////////////////////////////// 
    // splice temporary seen players to memory list 
    // temporary lists are cleared 
    M_teammates.splice(M_teammates.end(), 
             new_teammates); 
    M_opponents.splice(M_opponents.end(), 
             new_opponents); 
    // I've put some debug in this line 
    M_unknown_players.splice(M_unknown_players.end(), 
              new_unknown_players); 
    // And here too 
    
    ///////////////////////////////////////////////////////////////// 
        // create team member pointer vector for sort 
    
        PlayerPtrCont all_teammates_ptr; 
        PlayerPtrCont all_opponents_ptr; 
    
        { 
         const PlayerCont::iterator end = M_teammates.end(); 
         for (PlayerCont::iterator it = M_teammates.begin(); 
          it != end; 
          ++it) { 
          all_teammates_ptr.push_back(&(*it)); 
         } 
        } 
        { 
         const PlayerCont::iterator end = M_opponents.end(); 
         for (PlayerCont::iterator it = M_opponents.begin(); 
          it != end; 
          ++it) { 
          all_opponents_ptr.push_back(&(*it)); 
         } 
        } 
    
    ///////////////////////////////////////////////////////////////// 
        // sort by accuracy count 
        std::sort(all_teammates_ptr.begin(), 
           all_teammates_ptr.end(), 
           PlayerObject::PtrCountCmp()); 
        std::sort(all_opponents_ptr.begin(), 
           all_opponents_ptr.end(), 
           PlayerObject::PtrCountCmp()); 
    
    // I've put some more debug here 
    M_unknown_players.sort(PlayerObject::CountCmp()); 
    // And here 
    
    +0

    可以调用'posCount'和/或列表拼接以某种方式影响它将在下次输出的值吗? –

    +0

    @MikhailMaltsev posCount函数只是一个getter:'int posCount const {return pos_count; ''。我不认为这可能会造成干扰。 –

    +0

    也许列表已损坏?例如,如果你尝试在排序之前从'begin'到'end'和'rbegin'遍历'rend',它会发生段错误吗? –

    回答

    0

    好,事情是我最终解决问题我自己。

    显然这是一个巨大的bug集合的副作用。当我说巨大的时候,我的意思是几十个。未定义的行为是屁股真正的痛苦。

    像Valgrind这样的卫生消毒剂和软件无法正确识别代码是否有时会损坏堆栈内存。在这种情况下,排序功能只是访问已经损坏的链表。不知道如果有更多的精确/详细的工具。

    无论如何,谢谢大家。