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

时间:2016-03-03 13:39:34

标签: c++ templates c++11 stl

我使用模板编写跳过列表。当我运行它时,我在调用函数insert时遇到了分段错误。我用gdb调试它告诉我问题原因因为调用std::less<int>::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;
}

wroing message

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 个答案:

答案 0 :(得分:0)

问题与std::less<>无关。在此时的第一次insert()来电:

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

x是一个空指针。它解除引用会导致分段错误,而不是调用_M_keycmp中的任何内容。

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

  

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