C++11 动态分配的双链接循环列表类实例segc++;
当main使用dlring类型的构造变量进行操作时,使用此模板类的效果非常好,但我的目标是允许动态分配,因此我可以处理非预定义数量的双链接循环列表,以允许使用以下函数:C++11 动态分配的双链接循环列表类实例segc++;,c++11,linked-list,segmentation-fault,dynamic-programming,C++11,Linked List,Segmentation Fault,Dynamic Programming,当main使用dlring类型的构造变量进行操作时,使用此模板类的效果非常好,但我的目标是允许动态分配,因此我可以处理非预定义数量的双链接循环列表,以允许使用以下函数: 使用节点位置(通过 迭代)或值输入 将两个列表链接成一个具有单个头/尾的列表也是如此 配对 节点从一个列表(实例)导出到另一个列表(实例) 等等 我非常确定有一个优雅的解决方法,我还不知道,但我认为如果你没有努力解决问题,为社区提出一个问题是不好的。(点击谷歌) 因此,有了这些目标,我应该使用某种指向指针的指针(AFAIK)
- 使用节点位置(通过
迭代)或值输入 - 将两个列表链接成一个具有单个头/尾的列表也是如此 配对
- 节点从一个列表(实例)导出到另一个列表(实例)
- 等等
模板
类数据环
{
结构节点
{
T数据;
节点*prev;
节点*下一步;
node(T,node*p,node*n):数据(T),上一个(p),下一个(n){
};
节点*头;
节点*尾部;
公众:
dlring():head(nullptr),tail(nullptr){}
bool empty()常量{return(!head | | | tail)}
//运算符bool()常量{return!empty();}
空隙推力(T);
T弹回();
~dlring()
{
while(head)
{
节点*温度(头部);
头部=头部->下一步;
删除临时文件;
}
}
};
我应该使用注释掉的运算符bool重载吗
弹回和推送方法:
模板
void dlring::推送(T数据)
{
头部=新节点(数据、尾部、头部);
如果(头->下一步)
{
头部->下一步->上一步=头部;
尾部->下一个=头部;
}
if(空())
{
尾=头;
头部->下一个=尾部;
头部->前方=尾部;
尾部->下一个=头部;
尾部->上一个=头部;
}
}
模板
T dlring::pop_back()
{
if(空())
库特普雷夫;
如果(尾部!=温度)
{
尾部->下一步->下一步=头部;
头部->前方=尾部;
}
其他的
{
水头=零PTR;
tail=nullptr;
}
删除临时文件;
温度=零PTR;
返回数据;
}
我的尝试没有正确的行为:当我试图通过迭代显示所有列表时,代码失败,在dlist[0]的head->data access trument中出现segfaulting,其中0是k的迭代。下面是代码片段:
int main()
{
int k;
std::cout<<"Rings count?"<<std::endl;
std::cin>>k;
dlring<int>* dlist = new dlring<int>[k]; //I suppose I'm allocating *k*
//dlring<int> elements. this line is not confirmed to call the constructor.
(dlist[0]).Push(10);
(dlist[0]).Push(13);
(dlist[1]).Push(99);
/*{
while(!dlist[0].empty())
std::cout<<(dlist[0]).pop_back()<<" ";
std::cout<<std::endl;
while(!dlist[1].empty())
std::cout<<(dlist[1]).pop_back()<<" ";
}*/
//this section works perfectly fine, while this
for(int i=0;i<k;i++)
{
while(!dlist[k].empty())
std::cout<<(dlist[k]).pop_back()<<" ";
std::cout<<std::endl;
}
//is causing a segmentation fault while attempting to access dlist[*0*].tail->data.
std::cout<<(dlist[0]).head->data;
//line was checked and is confirmed to be functional,
//I suppose dlist[variable] has some trick I don't know yet.
//what I wish to look like an instance call would be *
return 0;
}
intmain()
{
int k;
标准::cout
由于dlist
是一个大小为k
的数组,因此原始代码生成一个越界访问
由于前面提到的循环使dlist
数组中的每个列表都为空,因此所有列表的头将是一个空指针。请注意,由于它是一个私有成员,因此您根本无法访问它。如果您这样做,则在取消引用它时将得到一个segfault:
std::cout<<(dlist[0]).head->data;
通过这些更改,我不会从clang的地址消毒剂中得到任何错误、问题或报告
另一个问题(在您的main
中没有体现)是pop\u back
中的tail
设置。我将尝试使用一些ASCII艺术进行说明。一个框
D ->
<- D
head->prev
指向与tail
相同的对象,类似地,tail->next
指向与head
相同的对象
现在,一个“动画”的pop_back
功能
template<typename T>
T dlring<T>::pop_back()
{
if( empty() )
std::cout<<"List empty";
node* temp(tail);
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^
|head |tail
|temp
*/
T data( tail->data );
tail = tail->prev ;
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^ ^
|head |tail |temp
*/
if (tail != temp)
{
tail->next->next = head;
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+ (A)
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^ ^
|head |tail |temp
The pointer (A) is what is changed when writing to tail->next->next.
Yes, nothing has actually changed in the list!
*/
head->prev = tail;
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+---------------------+
^ ^ ^
|head |tail |temp
*/
}
else
{
head = nullptr;
tail = nullptr;
}
delete temp;
/*
D -> D -> .. D ->
+- D <- D .. <- D
| ^
+---------------------+
^ ^ ^
|head |tail |temp
*/
temp = nullptr;
return data;
}
删除temp
(无进一步更改)后,它将如下所示:
/*
+---------------------+
v |
D -> D -> .. D -+
+- D <- D .. <- D
| ^
+---------------------+
^ ^ ^
|head |tail |temp
/*
+---------------------+
五|
D->D->…D-+
+-D在google://Overloading operators//Selector T*operator->{return m_obj;}//Address access T&operator*(){return*m_obj;}中漫游时发现此问题这有什么帮助吗?我认为pop\u back
中尾部的设置是不正确的:tail->next->next=head;
在这一点上,tail
已经指向了新的尾部,所以我会设置tail->next=head;
@dyp是的,但是要做新的tail->next=head我通过新的tail->next引用旧的tail。希望我没有弄错。也许我误解了tail
的目的,但我就是不明白:head->prev==tail&&tail->next==head
是否保证所有非空列表(当然是在成员函数之外)?如果是这样,为什么需要两个数据成员?如果牺牲一点空间并使用一个头节点(如果il不是集合的一部分),那么您的代码将更加简单和快速,因为可以从header节点访问极端值(head和tail)。并且您不必担心边界条件(push()为空列表,pop_back()为带一个元素的列表)。此外,如果在列表变为空之前使用pop_back(),则析构函数也更简单、更安全。请看一看我的main,我在尝试通过(dlist[k=0])调用pop_back访问数据(tail->data)时遇到segfault错误,但是(dlist[0])运行正常。请记住tail->data指的是“新”tail(从弹出结束或首次尝试弹出开始,两者都是合法的).P.S.:最后,我设法以一种可读的方式写下了这篇评论,只要我能对你的努力进行评价就好了。非常感谢你的关注。@Гааааааааааааааааааааааа这两个额外的变化,我很有信心,程序应该运行良好。请看我的答案的开头。好的,我们这里有一个很好的实现
std::cout<<(dlist[0]).head->data;
delete[] dlist;
D ->
<- D
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^
|head |tail
template<typename T>
T dlring<T>::pop_back()
{
if( empty() )
std::cout<<"List empty";
node* temp(tail);
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^
|head |tail
|temp
*/
T data( tail->data );
tail = tail->prev ;
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^ ^
|head |tail |temp
*/
if (tail != temp)
{
tail->next->next = head;
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+ (A)
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^ ^
|head |tail |temp
The pointer (A) is what is changed when writing to tail->next->next.
Yes, nothing has actually changed in the list!
*/
head->prev = tail;
/*
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+---------------------+
^ ^ ^
|head |tail |temp
*/
}
else
{
head = nullptr;
tail = nullptr;
}
delete temp;
/*
D -> D -> .. D ->
+- D <- D .. <- D
| ^
+---------------------+
^ ^ ^
|head |tail |temp
*/
temp = nullptr;
return data;
}
if (tail != temp)
{
tail->next = head;
/*
+---------------------+-------+
v | |
D -> D -> .. D -+ D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^ ^
|head |tail |temp
/*
+---------------------+
v |
D -> D -> .. D -+
+- D <- D .. <- D
| ^
+---------------------+
^ ^ ^
|head |tail |temp