好的,所以我一直在研究一些书籍的例子和内容,并发现这个练习实现了STL List。我已经以某种方式做到了它有点工作,但我在实施中遇到了一些重大缺陷。
最大的一点就是我完全不知道如何使我的List.end()迭代器按照它应该做的那样工作。
我想我会先显示代码,然后尝试告诉我的一些想法。
#ifndef TESTS_LST_H
#define TESTS_LST_H
#include <memory>
#include <cstddef>
template<class T> class Node;
template<class T> class ListIter;
template<class T>
class List {
public:
typedef ListIter<T> iterator;
typedef const ListIter<T> const_iterator;
typedef std::size_t size_type;
List(): first(0), last(0), sz(0) {}
List(const List<T>& lst);
~List() { clear(); }
iterator begin() { return iterator(first); }
iterator end() { return iterator(last); }
iterator insert() {}
iterator erase() {}
const_iterator begin() const { return iterator(first); }
const_iterator end() const { return iterator(last); }
void push_back(const T& val);
void push_front(const T& val);
void clear();
void pop_front();
void pop_back();
size_type size() { return sz; }
bool empty() { return sz == 0; }
List& operator=(const List& l);
private:
Node<T>* first;
Node<T>* last;
size_type sz;
std::allocator<Node<T>>* alloc;
};
template<class T>
class Node {
public:
Node(): next(0), prev(0), value(0) {}
Node(const T& val): next(0), prev(0), value(val) {}
private:
Node<T>* next;
Node<T>* prev;
T value;
friend class List<T>;
friend class ListIter<T>;
};
template<class T>
class ListIter {
public:
typedef ListIter<T> iterator;
ListIter(Node<T>* iter): current_node(iter) {}
ListIter(): current_node(0) {}
ListIter(ListIter<T>* iter): current_node(iter->current_node) {}
inline T& operator*() { return current_node->value; }
iterator& operator=(const iterator& rhs) { *this->current_node = rhs.current_node; }
bool operator==(const iterator& rhs) { return current_node->value == rhs.current_node->value; }
bool operator!=(const iterator& rhs) { return current_node->value != rhs.current_node->value; }
iterator& operator++();
iterator operator++(int);
iterator& operator--();
iterator operator--(int);
private:
Node<T>* current_node;
friend class List<T>;
};
template<class T>
void List<T>::push_back(const T& val)
{
Node<T>* temp = alloc->allocate(1);
alloc->construct(temp, val);
if (first == 0) {
first = last = temp;
} else {
temp->prev = last;
last->next = temp;
last = temp;
}
sz++;
}
template<class T>
void List<T>::push_front(const T &val)
{
Node<T>* temp = alloc->allocate(1);
alloc->construct(temp, val);
if (first == 0) {
first = last = temp;
} else {
temp->prev = 0;
temp->next = first;
first->prev = temp;
first = temp;
}
sz++;
}
template<class T>
void List<T>::clear()
{
Node<T>* current = first;
while (current != 0) {
Node<T>* next = current->next;
//delete current
alloc->deallocate(current, 1);
alloc->destroy(current);
current = next;
}
first = last = 0;
sz = 0;
}
template<class T>
List<T>::List(const List &lst)
{
first = last = 0;
sz = 0;
for (auto it = lst.begin(); it != lst.end(); it++) {
push_back(it.current_node->value);
}
push_back(lst.last->value);
}
template<class T>
List<T>& List<T>::operator=(const List &lst)
{
first = last = 0;
sz = 0;
for (auto it = lst.begin(); it != lst.end(); ++it) {
push_back(it.current_node->value);
}
push_back(lst.last->value);
return *this;
}
template<class T>
void List<T>::pop_front()
{
first = first->next;
alloc->deallocate(first->prev, 1);
alloc->destroy(first->prev);
first->prev = 0;
sz--;
}
template<class T>
void List<T>::pop_back()
{
last = last->prev;
alloc->deallocate(last->next, 1);
alloc->destroy(last->next);
last->next = 0;
sz--;
}
template<class T>
ListIter<T>& ListIter<T>::operator++()
{
current_node = current_node->next;
return *this;
}
template<class T>
ListIter<T>& ListIter<T>::operator--()
{
current_node = current_node->prev;
return *this;
}
template<class T>
ListIter<T> ListIter<T>::operator++(int)
{
iterator tmp(*this);
++*this;
return tmp;
}
template<class T>
ListIter<T> ListIter<T>::operator--(int)
{
iterator tmp(*this);
--*this;
return tmp;
}
#endif //TESTS_LST_H
正如你所看到的.end()函数返回列表的常规最后一个元素,而不是它应该返回的结尾。
我是否应该尝试重新编写这一部分,以便将* last保留为结束迭代器之后的一个,并使用operator +迭代列表以省略指向实际列表末尾的指针的需要?
这样的事情(不确定下面代码的核心性):
iterator& operator+(std::size_type n)
{
for (auto i = 0; i < n; ++i) {
++*this;
}
return *this;
}
但是我不确定这些东西在实际实现中是如何工作的,毕竟循环可能非常苛刻。 我知道这些东西已经存在并且可以正常工作。这只是出于教育目的,所以我希望听到一些想法。提前谢谢。
答案 0 :(得分:0)
Iterator在过去被称为&#34;智能指针&#34;,因为它们就是这样的。 (实际上,指针是迭代器,但不是反对者)。所以,想一个像指针一样的迭代器。
&#34;一个接一个结束&#34;很清楚当你使用向量时意味着什么:vector
在连续的空间中包含它的元素。实际上,可以用指针实现向量迭代器。但是对于链接的list
来说情况并非如此,其中元素通常不在连续的内存中。
由于您已将List
类实现为双重链接列表,因此建议您更改first
和last
指针:
template<class T>
class List {
// ...
private:
Node<T> head;
size_type sz;
};
因此,begin()
迭代器变为head.next
,end()
迭代器变为&head
。这可以用于列表中的最后一个元素指向head
。
顺便说一句:您不需要在朋友课程中创建Node<T>
作为class
。这只是一个实现细节。将其更改为struct
并将其放入实施namespace
。