2017-10-09 78 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這樣的衛生消毒劑和軟件無法正確識別代碼是否有時會損壞堆棧內存。在這種情況下,排序功能只是訪問已經損壞的鏈表。不知道如果有更多的精確/詳細的工具。

    無論如何,謝謝大家。

    相關問題