使用模板调用 std::less<int>::operator() 导致分段错误

Posted

技术标签:

【中文标题】使用模板调用 std::less<int>::operator() 导致分段错误【英文标题】:Using template call std::less<int>::operator() cause segmentation fault 【发布时间】:2016-03-03 13:39:34 【问题描述】:

我使用模板来编写跳过列表。当我运行它时,当我调用函数insert 时出现分段错误。我用gdb 调试它告诉我问题原因,因为调用std::less&lt;int&gt;::operator()。我看到了example,但我仍然是我的原因错误的。 skiplist.h:

#include <iostream>
#include <cstring>
namespace IceCity
    const double DEFAULT_PROBILITY = 1/4;
    const int    DEFAULT_MAXSIZE   = 16;
    //node base
    template <typename KeyValue,typename Value>
    struct sklist_node 
    
        KeyValue key;
        Value value;
        sklist_node<KeyValue,Value>** forward;
    ;
    template <typename KeyValue,typename Value,
             typename KeyCmp = std::less<KeyValue> , 
             typename ValueCmp = std::equal_to<Value> >
    class sklist
    
    public:     
        sklist (int limitlevel = DEFAULT_MAXSIZE, double pro = DEFAULT_PROBILITY) :
            _M_limitlevel(limitlevel), _M_pro(pro)
        
            _M_maxlevel = 0;    
            _M_header = make_node(limitlevel, 0, 0);
        
        virtual ~sklist ()
        
            //TODO:free
            _M_NodePointer x = _M_header;
            _M_NodePointer tmp = x->forward[0];
            while (tmp != nullptr) 
            
                delete x;   
                x = tmp;
                tmp = tmp->forward[0];
            ;      
        
    //Data member
    private:
        typedef  sklist_node<KeyValue,Value>    _M_Node;
        typedef  sklist_node<KeyValue,Value>*   _M_NodePointer;
        typedef  Value*                         _M_ValuePoiner;
        int                                     _M_limitlevel;
        double                                  _M_pro;
        _M_NodePointer                          _M_header;
        KeyCmp                                  _M_keycmp;
        ValueCmp                                _M_valuecmp;
        int                                     _M_maxlevel;    
    //private member function
    private:
        /****
        * make a node with level and key *
        ****/
        inline _M_NodePointer
        make_node(int level, KeyValue key, Value value) 
        
            _M_NodePointer res      = new _M_Node;
            res->key            = key;
            res->value          = value;
            res->forward        = new _M_NodePointer [level+1];
            return res;
        

        /****
        * creat an rand number [0.0,1.0) *
        ****/
        inline double 
        random_pro()
        
            return static_cast<double>(rand())/RAND_MAX;
        

        /****
        * get the level for a node *
        ****/
        int 
        random_level()
        
            int level = 0;
            while ( random_pro() < _M_pro && level < _M_limitlevel ) 
            
                level++;    
            
            return level;
        
    public:
        /****
        * insert an node in skiplist *
        ****/
        void 
        insert(KeyValue key, Value NewValue)
        
            _M_NodePointer x = _M_header;
            _M_NodePointer update[_M_limitlevel+1];
            memset( update, 0, _M_limitlevel+1 );
            for(int i = _M_maxlevel; i >=0 ; --i)   
            
                while (x->forward[i] != nullptr && _M_keycmp(x->forward[i]->key, key)) 
                
                    x = x->forward[i];  
                
                update[i] = x;
            
            x = x->forward[0];
            /****
            * if x->key equal to search key update it
            * else insert it*
            ****/

            if ( _M_keycmp(x->key, key) ) 
            
                x->value = NewValue;    
            
            else 
            
                int level = random_level();
                if ( level > _M_maxlevel ) 
                
                    for(int i = _M_maxlevel+1; i <= level; ++i) 
                    
                        update[i] = _M_header;  
                    
                    // update maxlevel
                    _M_maxlevel = level;
                
                x = make_node( level, key, NewValue );
                for( int i = 0; i <= level; ++i )
                
                    x->forward[i] = update[i]->forward[i];  
                    update[i]->forward[i] = x;
                
            
           
    ;

#endif /* ifndef IC_BASE_LIST */

skiplist.cpp:

#include "base_list.h"
#include <iostream>
int main(int argc, char *argv[])

    IceCity::sklist<int, int> ss;

    for (int i = 0; i < 20; ++i) 
        ss.insert(i, i*10); 
    
    return 0;

错误消息

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401894 in std::less<int>::operator()(int const&, int const&) const ()
[0] from 0x0000000000401894 in std::less<int>::operator()(int const&, int const&) const
(no arguments)
[1] from 0x0000000000401286 in IceCity::sklist<int, int, std::less<int>, std::equal_to<int> >::insert(int, int)
(no arguments)

【问题讨论】:

【参考方案1】:

问题与std::less&lt;&gt;无关。此时在您的第一个insert() 呼叫中:

if ( _M_keycmp(x->key, key) ) 

x 是一个空指针。正是取消引用导致了分段错误,而不是对 _M_keycmp 的调用中的任何内容。


旁注:您所有的成员名称都是 C++ 中的保留字。来自 [lex.name]:

每个包含双下划线__或以下划线后跟大写字母的标识符都保留给实现以供任何使用。

【讨论】:

以上是关于使用模板调用 std::less<int>::operator() 导致分段错误的主要内容,如果未能解决你的问题,请参考以下文章

我的C/C++语言学习进阶之旅解决使用algorithm库里面的sort函数的时候,编译报错:未能使函数模板“unknown-type std::less<void>::operator ()(代码片

我的C/C++语言学习进阶之旅解决使用algorithm库里面的sort函数的时候,编译报错:未能使函数模板“unknown-type std::less<void>::operator ()(代码片

如何确保订购std :: map?

为啥 std::compare_three_way 不是模板结构/函子

在使用 g++ 创建的共享库中隐藏实例化模板

在带有模板的结构中,为啥左值会推导出为右值?