template <class T>
class list
{
public:
//stuff
list(const list &cctorList); //cctor
private:
struct node
{
node *next;
node *previous;
T *info;
}
node *firstNode; //pointer to the first node (NULL if none)
node *lastNode; //pointer to the last node (NULL if none)
}
我现在正在尝试定义list(const list &cctorList); //cctor
,但我遇到了麻烦。
这是我到目前为止所拥有的:
template <class T>
list<T>::list(const list &cctorList)
{
node *another = new node;
firstNode = another;
another->previous = NULL;
another->info = new T(*(cctorList->info));
// ...
}
这一切是否正确?有没有办法让我递归分配another->next
?另外,使用迭代器是否有更简单的方法来实现这一点?
答案 0 :(得分:2)
您应该使用std::list
。实际上,您应该使用std::vector
,因为它对于大多数实际用途来说更快(如果对象真的很大或者构造起来非常昂贵,列表只会更快)并且您不需要随机访问。
new T(*(cctorList->info));
无法编译,因为cctorList
(list&
)没有operator->
,也没有info
成员。
复制构造函数最好根据push_back
和迭代等其他更原始的操作实现。所以首先要做的就是复制构造函数:
template <class T>
list<T>::list(const list &cctorList)
{
std::copy(begin(cctorList), end(cctorList), std::back_inserter(this));
}
实际上我只是模板构造函数:
template <class T, class Collection> list(const Collection &cctorList)
(身体保持不变)。它可以作为复制构造函数,但也允许从任何可以隐式转换为T的类型的任何其他集合进行复制。
实际数据应由值保存。即node
应定义为
struct node
{
node *next;
node *previous;
T info;
}
您正在复制该值,因此您无需为node
和T
分别进行两次分配。
编辑:你说你想学习概念。但现代C ++最重要的概念是算法组合。他们的定义通常是微不足道的。 std::copy
的基本实现只是:
template <typename InputIterator, typename OutputIterator>
OutputIterator copy(InputIterator begin, InputIterator end, OutputIterator out) {
for(;begin != end; ++out, ++begin) *out = *begin;
}
现在这似乎没有分配任何东西。诀窍在于back_insertion_iterator
。插入迭代器是一种技巧,可以在不预先分配序列的情况下完成这项工作。它使用基础集合上的operator*
定义push_back
并忽略operator++
。这满足了“输出迭代器”的概念,因为它只保证在这两个调用被严格交错时工作,并使算法可以处理从普通旧数组到输出流的许多事情。
另一部分是,虽然平凡的定义是正确的,但它们不是库中使用的实际定义。库中的实际定义已经过优化。例如。通常std::copy
将检查输入迭代器是否知道它们的距离以及输出是否为插入操作符以使用reserve
操作进行排序并调用它以避免某些分配。这些都是优化,取决于标准库的实现细节。
您可以从标准库中记下事物的基本实现,如果您想了解它们,测试它们的工作原理是相同的。但是你应该遵循标准库定义的方式,通过简单的帮助位来构建它们,例如std::copy
,std::swap
,插入迭代器适配器等。如果你查看标准库,那么大多数函数都是单行的!
Edit2:同样具有标准库提供的所有通用性,仍有一些人因为不够通用而受到批评。例如。 GotW #84: Monoliths "Unstrung"讨论了std::string
的哪些方法可以转换为通用算法。