Using this template class works perfectly fine when main operates with constructed variables of type dlring, yet my goal is to allow dynamic allocation, so I can handle a non-predefined number of doubly linked circular lists to allow usage of such functions as:
I'm pretty much sure there is an elegant workaround which is simply not known by me yet, but I don't think it's nice to come up with a question for the community if you didn't struggle enough to resolve. (checked google
So with that goals I'm supposed to dynamically allocate memory (via constructor calls) using some kind of pointer-to-pointer, AFAIK. If there is a smarter way to implement these, please let me know. My solution attempt is given in the end of this snippet. Feel free to criticize all of the below.
Echo "Please enter name: "
read name
read -r -p "Is this a costumer? (Y/N)" response;
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo "Please enter name: "
read name
AreYouDone
else
"Please enter name "
read name2
AreYouDone
fi
echo $name is a costumer
echo $name2 is an employer
Should I use the commented out operator bool overload?
template <typename T>
class dlring
{
struct node
{
T data;
node* prev;
node* next;
node(T t, node* p, node* n) : data(t), prev(p), next(n) {}
};
node* head;
node* tail;
public:
dlring():head(nullptr), tail(nullptr){}
bool empty() const { return ( !head || !tail ); }
//operator bool() const { return !empty(); }
void Push(T);
T pop_back();
~dlring()
{
while(head)
{
node* temp(head);
head=head->next;
delete temp;
}
}
};
My attempt doesn't have the right behaviour: When I'm trying to show all the lists via a iteration the code fails, segfaulting on head->data access attempt of dlist[0], where 0 is an iteration of k. Here is the snippet:
template <typename T>
void dlring<T>::Push(T data)
{
head = new node(data, tail, head);
if( head->next )
{
head->next->prev = head;
tail->next = head;
}
if( empty() )
{
tail = head;
head->next=tail;
head->prev=tail;
tail->next=head;
tail->prev=head;
}
}
template<typename T>
T dlring<T>::pop_back()
{
if( empty() )
std::cout<<"List empty";
node* temp(tail);
T data( tail->data );
tail = tail->prev ;
if (tail != temp)
{
tail->next->next = head;
head->prev = tail;
}
else
{
head = nullptr;
tail = nullptr;
}
delete temp;
temp = nullptr;
return data;
}
Best regards. Again, feel free to criticize any of my code/logics.
答案 0 :(得分:0)
for(int i=0;i<k;i++)
{
while(!dlist[k].empty())
std::cout<<(dlist[k]).pop_back()<<" ";
std::cout<<std::endl;
}
没有使用迭代器i
。它应该是:
for(int i=0;i<k;i++)
{
while(!dlist[i].empty())
std::cout<<(dlist[i]).pop_back()<<" ";
std::cout<<std::endl;
}
由于dlist
是一个大小为k
的数组,原始代码会产生越界访问。
由于前面提到的循环使dlist
数组中的每个列表都为空,因此所有列表中的head
都是空指针。请注意,您根本无法访问它,因为它是私有成员。如果您这样做,则在解除引用时会出现段错误:
std::cout<<(dlist[0]).head->data;
如果在程序的这一点编译dlist[0].head == nullptr
,那么就会出现段错误。
另请注意,由于您未发布动态分配的dlist
,因此您会泄漏内存。附加到您的程序结束:
delete[] dlist;
通过这些更改,我不会从clang的地址清理工具中获得任何段错误,问题或报告。
另一个问题(在main
中没有表现出来)是在tail
中设置pop_back
。我将尝试使用一些ASCII艺术作为插图。一个方框
D ->
<- D
表示具有Data的节点,next
指针和prev
指针。
所有箭头都是指针。
非空列表:
+-----------------------------+
v |
D -> D -> .. D -> D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^
|head |tail
head->prev
指向与tail
相同的对象,类似地,tail->next
指向与head
相同的对象。
现在,一个&#34;动画&#34; 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;
}
请注意,在最后一张&#34;图片&#34;中,tail->next
是一个无效指针。
相反,它应该是:
if (tail != temp)
{
tail->next = head;
/*
+---------------------+-------+
v | |
D -> D -> .. D -+ D -+
+- D <- D .. <- D <- D
| ^
+-----------------------------+
^ ^ ^
|head |tail |temp
删除temp
后(没有进一步的更改),它将如下所示:
/*
+---------------------+
v |
D -> D -> .. D -+
+- D <- D .. <- D
| ^
+---------------------+
^ ^ ^
|head |tail |temp
最后但同样重要的是,请注意您违反了Rule of Three。