我必须在GetHead()
和GetTail()
中返回列表的开头和结尾。
我试图自己返回头部和尾巴并得到错误:
cannot initialize return object of type 'int' with an lvalue of type 'Node<int> *const'
return tail;
我还尝试返回head->value
和tail->value
,它在EXC_BAD_ACCESS
中给了string() const
。
template<typename T>
class Node
{
private:
T value;
Node* prev;
Node* next;
public:
Node(T value, Node* prev = NULL, Node* next = NULL);
friend class List<T>;
};
template<typename T>
class List
{
private:
Node<T>* head;
Node<T>* tail;
public:
List();
List(const List<T>& src);
~List();
bool IsEmpty() const;
T GetHead() const;
T GetTail() const;
void AddToHead(T v);
void AddToTail(T v);
bool RemoveHead();
bool RemoveTail();
operator string() const;
///////////////////////////////////////////
// Do not change the above prototype.
// Add member function(s) below if you need.
// Do not change the below.
///////////////////////////////////////////
};
template<typename T>
Node<T>::Node(T value, Node* prev, Node* next)
{
this->value = value;
this->prev = prev;
this->next = next;
}
template<typename T>
List<T>::operator string() const
{
if (IsEmpty())
return "()";
stringstream os;
os << "(";
Node<T>* r = head;
while (r != tail)
{
os << r->value << ",";
r = r->next;
}
os << r->value << ")";
string str = os.str();
return str;
}
template<typename T>
List<T>::List()
{
// make list empty
head = tail = NULL;
}
template<typename T>
List<T>::List(const List<T>& src)
{
// make list empty
head = tail = NULL;
// copy all contents in src into this
Node<T>* node = src.head;
while(node != NULL)
{
AddToTail(node->value);
node = node->next;
}
}
template<typename T>
bool List<T>::IsEmpty() const
{
return (head == NULL);
}
///////////////////////////////////////////
// Do not change the above.
// Implement your own member functions below.
template<typename T>
List<T>::~List()
{
while (!IsEmpty())
RemoveTail();
}
template<typename T>
void List<T>::AddToTail(T v)
{
if (IsEmpty())
head = tail = new Node<T>(v, NULL, NULL);
else
{
head = new Node<T>(v, tail, NULL);
head->prev->next = tail;
}
}
template<typename T>
void List<T>::AddToHead(T v)
{
if (IsEmpty())
head = tail = new Node<T>(v, NULL, NULL);
else
{
head = new Node<T>(v, NULL, head);
head->next->prev = head;
}
}
template<typename T>
bool List<T>::RemoveHead()
{
if(IsEmpty())
return false;
if(head == tail)
{
delete tail;
head = tail = NULL;
return true;
}
else
{
head = head->next;
delete head->prev;
head->prev = NULL;
return true;
}
}
template<typename T>
bool List<T>::RemoveTail()
{
if(IsEmpty())
return false;
if(head == tail)
{
delete tail;
head = tail = NULL;
return true;
}
else
{
tail = tail->prev;
delete tail->next;
tail->next = NULL;
return true;
}
}
template<typename T>
T List<T>::GetHead() const
{
return head;
}
template<typename T>
T List<T>::GetTail() const
{
return tail;
}
答案 0 :(得分:1)
您自己不能返回head
/ tail
,因为返回类型为T
,所以您必须返回内容。
关于使用EXC_BAD_ACCESS
时为何在string() const
中得到->value
的问题,AddToTail
中存在一个主要问题。如果您仅添加了一个元素,则head
和tail
是同一指针,其中prev
的{{1}}和next
。然后,您可以这样做:
NULL
使用 head = new Node<T>(v, tail, NULL);
的{{1}}和prev
的{{1}}组成一个新元素,并将该新元素设为新的tail
(因此因为next
替换了NULL
?!?),所以有些奇怪。
下一步
head
采用新元素,找到它的AddToTail
(当前的head
/旧的 head->prev->next = tail;
)并说其prev
是tail
。因此,新的head
的{{1}}的{{1}}(从未设置),next
的{{1}}和tail
本身都有一个head
本身(因此,如果您从next
返回,然后再尝试前进,则会陷入无限循环)。
来自NULL
的无限循环甚至不是这里的问题。问题是来自prev
的{{1}}路径命中tail
却从未见过tail
。如果您尝试next
,它将从head
开始并继续tail
,直到达到next
(如果列表构造正确,这是一个合理的假设)。但它从未到达head
,只是碰到NULL
并死于试图读取tail
,这显然是坏的。
您需要修复operator string()
,以便创建合法的head
。并可能在向next
遍历的代码中添加tail
,以寻找tail
来验证它在命中NULL
之前没有命中NULL->value
。我相信解决方法是将AddToTail
的{{1}}大小写更改为:
List
但一定要重新检查您的逻辑并在可能的情况下适当添加assert
。