C++ STL-like skiplist实现的Seg错误

C++ STL-like skiplist实现的Seg错误,c++,stl,skip-lists,C++,Stl,Skip Lists,我正在实现STL风格的skiplist。内部节点类型如下所示: template <class N> struct __skiplist_node { typedef __skiplist_node<N>* __skiplist_node_pointer; N data; __skiplist_node_pointer prev; std::list<__skiplist_node_pointer> nexts; }; 模板 结构skipli

我正在实现STL风格的skiplist。内部节点类型如下所示:

template <class N>
struct __skiplist_node
{
  typedef __skiplist_node<N>* __skiplist_node_pointer;
  N data;
  __skiplist_node_pointer prev;
  std::list<__skiplist_node_pointer> nexts;
};
模板
结构skiplist节点
{
typedef _skiplist_node*_skiplist_node_指针;
N数据;
__skiplist_node_pointer prev;
std::列出nexts;
};
内部节点中有std::list。 当我想将一个uuu skiplist_节点推回到下一个列表中时。在运行时构造skiplist时。它遇到了分段故障。调试回溯显示:

#0  0x00007ffff63a6acf in std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x000000000045e0f6 in _M_insert (this=<optimized out>, __x=<optimized out>, 
    __position=...) at /usr/include/c++/4.8/bits/stl_list.h:1554
#2  push_back (__x=<optimized out>, this=<optimized out>)
    at /usr/include/c++/4.8/bits/stl_list.h:1016
#3  repo::SkipList<ndn::Name, repo::tests::DatasetBase::DataSetNameCompare>::empty_initialize (this=<optimized out>)
    at /home/chenatu/workspace/repo-ng/src/storage/skiplist.hpp:118
#4  0x000000000045ed1b in SkipList (this=0x7fffffffcfd0)
    at /home/chenatu/workspace/repo-ng/src/storage/skiplist.hpp:124
#5  repo::tests::SkipList::NdnNameSkipList<repo::tests::BaseTestFixture>::test_method (this=this@entry=0x7fffffffd070) at ../tests/unit/skiplist.cpp:40
#6  0x000000000045efd9 in run<repo::tests::BaseTestFixture> ()
    at ../tests/unit/skiplist.cpp:38
#7  operator() (this=<optimized out>)
    at /usr/include/boost/test/unit_test_suite_impl.hpp:357
#8  invoke<boost::unit_test::ut_detail::test_case_template_invoker<repo::tests::SkipList::NdnNameSkipList_invoker, repo::tests::BaseTestFixture> > (
    this=<optimized out>, f=...)
    at /usr/include/boost/test/utils/callback.hpp:56
#0 0x00007FF63A6ACF标准::u详情::u列表u节点u库::u钩子(标准::u详情::u列表u节点u库*)()来自/usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x000000000045e0f6 in_M_insert(this=,__x=,
__位置=…)位于/usr/include/c++/4.8/bits/stl_list.h:1554
#2推回(uux=,this=)
at/usr/include/c++/4.8/bits/stl_list.h:1016
#3 repo::SkipList::empty\u初始化(this=)
at/home/chenatu/workspace/repo ng/src/storage/skiplist.hpp:118
#SkipList中的4 0x000000000045ed1b(该值=0x7fffffffcfd0)
at/home/chenatu/workspace/repo ng/src/storage/skiplist.hpp:124
#5 repo::tests::SkipList::NdnNameSkipList::test_方法(此=this@entry=0x7fffffffd070)在../tests/unit/skiplist.cpp:40处
#运行中的6 0x000000000045efd9()
在../tests/unit/skiplist.cpp时:38
#7运算符()(this=)
at/usr/include/boost/test/unit_test_suite_impl.hpp:357
#8调用(
this=,f=…)
at/usr/include/boost/test/utils/callback.hpp:56
我想知道的是,如何为这个内部节点动态分配资源

下面是完整的代码:

#ifndef REPO_STORAGE_SKIPLIST_HPP
#define REPO_STORAGE_SKIPLIST_HPP

#include "common.hpp"

#include <boost/utility.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>

namespace repo {

static const size_t SKIPLIST_MAX_LAYERS = 32;
static const double SKIPLIST_PROBABILITY = 0.25; // 25% (p = 1/4)

template<typename T, typename Compare = std::less<T> >
class SkipList
{
public:
  template <class N>
  struct __skiplist_node
  {
    typedef __skiplist_node<N>* __skiplist_node_pointer;
    N data;
    __skiplist_node_pointer prev;
    std::list<__skiplist_node_pointer> nexts;
  };

  class iterator : public std::iterator<std::bidirectional_iterator_tag, T>
  {
  public:
    typedef __skiplist_node<T>* link_type;
    link_type node;
    // constructor
    iterator(link_type x) : node(x) {}
    iterator() {}
    iterator(const iterator& x) : node(x.node) {}
    bool operator == (const iterator& x) const { return node == x.node; }
    bool operator != (const iterator& x) const { return node != x.node; }

    typename std::iterator<std::bidirectional_iterator_tag, T>::reference operator * () const
      { return (*node).data; }
    typename std::iterator<std::bidirectional_iterator_tag, T>::pointer operator -> () const
      { return &(operator*()); }
    iterator& operator ++ () {
      node = (link_type)(*((*node).nexts.begin()));
      return *this;
    }
    iterator& operator -- () {
      node = (link_type)((*node).prev);
      return *this;
    }
  };

protected:
  typedef __skiplist_node<T> skiplist_node;
public:
  typedef skiplist_node* link_type;
protected:
  link_type node;
  std::allocator<skiplist_node> skiplist_allocator;

  link_type
  get_node()
  {
    return skiplist_allocator.allocate(sizeof(skiplist_node));
  }

  void
  put_node(link_type p)
  {
    skiplist_allocator.deallocate(p);
  }

  link_type
  create_node(const T& x)
  {
    link_type p = get_node();
    construct(&p->data, x);
    return p;
  }

  void
  destroy_node(link_type p)
  {
    destroy(&p->data);
    put_node(p);
  }

  void
  empty_initialize()
  {
    node = get_node();
    node->prev = node;
    node->nexts.push_back(node);
  }
public:
  explicit
  SkipList()
  {
    empty_initialize();
  }

  ~SkipList() {}

public:
  iterator begin() const { return (link_type)(*(*node).nexts.begin()); }

  iterator end() const { return node; }

  bool empty() const { return *(node->nexts.begin()) == node; }

  size_t size() const
  {
    size_t result = 0;
    result = std::distance(begin(), end());
    return result;
  }

};
} // namespace repo
#endif // REPO_STORAGE_SKIPLIST_HPP
\ifndef REPO\u STORAGE\u SKIPLIST\u水电站
#定义REPO\u STORAGE\u SKIPLIST\u水电站
#包括“common.hpp”
#包括
#包括
#包括
名称空间回购{
静态常量大小\u t SKIPLIST\u MAX\u层=32;
静态常数双SKIPLIST_概率=0.25;//25%(p=1/4)
模板
职业技工
{
公众:
模板
结构skiplist节点
{
typedef _skiplist_node*_skiplist_node_指针;
N数据;
__skiplist_node_pointer prev;
std::列出nexts;
};
类迭代器:public std::iterator
{
公众:
typedef\uu skiplist\u节点*链接类型;
链接类型节点;
//建造师
迭代器(link_type x):节点(x){}
迭代器(){}
迭代器(constiterator&x):节点(x.node){}
布尔运算符==(常量迭代器&x)常量{return node==x.node;}
布尔运算符!=(常量迭代器&x)常量{return node!=x.node;}
typename std::迭代器::引用运算符*()常量
{return(*node).data;}
typename std::iterator::指针运算符->()常量
{return&(operator*());}
迭代器和运算符++(){
node=(link_type)(*((*node.nexts.begin());
归还*这个;
}
迭代器和运算符--(){
node=(link_type)((*node.prev);
归还*这个;
}
};
受保护的:
类型定义\uuuu skiplist\u节点skiplist\u节点;
公众:
typedef skiplist_节点*link_类型;
受保护的:
链接类型节点;
std::分配器skiplist\u分配器;
链接类型
获取节点()
{
返回skiplist_分配器.allocate(sizeof(skiplist_节点));
}
无效的
放置节点(链接类型p)
{
skiplist_分配器.释放(p);
}
链接类型
创建_节点(常量T&x)
{
link_type p=get_node();
构造(&p->data,x);
返回p;
}
无效的
销毁节点(链接类型p)
{
销毁(&p->数据);
put_节点(p);
}
无效的
空_initialize()
{
node=get_node();
节点->上一个=节点;
节点->下一步。推回(节点);
}
公众:
明确的
斯基普利斯特()
{
空_初始化();
}
~SkipList(){}
公众:
迭代器begin()常量{return(link_type)(*(*node).nexts.begin());}
迭代器end()常量{return node;}
bool empty()const{return*(node->nexts.begin())==node;}
大小\u t大小()常量
{
大小\u t结果=0;
结果=标准::距离(开始(),结束());
返回结果;
}
};
}//命名空间repo
#endif//REPO\u STORAGE\u SKIPLIST\u水电站
错误在这里:

  link_type
  get_node()
  {
    return skiplist_allocator.allocate(sizeof(skiplist_node));
  }

  link_type
  create_node(const T& x)
  {
    link_type p = get_node();
    construct(&p->data, x);
    return p;
  }
allocate
只分配内存,不初始化内存。您必须调用construct对其进行初始化,但只能对
数据
执行此操作,而不能对节点的其他部分执行此操作


因此,您从未构建过
std::list
,只是为其分配了内存,因此在尝试使用此未初始化内存时,会遇到未定义的行为。

skiplist\u分配器的类型定义为。你的意思是它无法初始化节点?我不太明白你的意思。你是说所有的部分都没有初始化,或者只是数据被初始化?如何初始化std::list成员?谢谢大家!@chenatu:分配器有两种方法,
allocate
分配内存和
construct
初始化内存;由于您只调用了
allocate
,因此您得到了原始内存(对于该类型而言,具有合适的大小和对齐方式,但为原始内存)。我可以使用“skiplist\u分配器.construct(&(p->nexts),std::list());”来初始化列表吗?它不能通过考试compiling@chenatu:否,
construct
已经知道它应该构造的元素的类型,因为已键入分配器。请参阅:使用元素的地址(分配给您的
元素)和要复制的内容或构造函数的参数列表调用它。