6

我需要为我的程序使用列表,并且需要决定是使用 std::vector 还是 std::list。vector 的问题是没有 remove 方法,而 list 的问题是没有运算符 []。所以我决定编写自己的类来扩展 std::list 并重载 [] 运算符。

我的代码如下所示:

#include <list>

template <class T >
class myList : public std::list<T>
{
public:
T operator[](int index);
T operator[](int & index);
myList(void);
~myList(void);
};

#include "myList.h"

template<class T>
myList<T>::myList(void): std::list<T>() {}

template<class T>
myList<T>::~myList(void)
{
std::list<T>::~list();
}

template<class T>
T myList<T>::operator[](int index) {
int count = 0;
std::list<T>::iterator itr = this->begin();
while(count != index)itr++;
return *itr;    
}

template<class T>
T myList<T>::operator[](int & index) {
int count = 0;
std::list<T>::iterator itr = this->begin();
while(count != index)itr++;
return *itr;
}

我可以编译它,但如果我尝试使用它,我会收到链接器错误。有任何想法吗?

4

8 回答 8

52

根据您的需要,您应该使用std::vector(如果您需要经常在末尾添加/删除,以及随机访问),或者std::deque(如果您需要经常在末尾或开头添加/删除,并且您的数据集很大,并且仍然想要随机访问)。这是一张很好的图片,向您展示了如何做出决定:

容器选择
(来源:adrinael.net

于 2008-12-14T16:44:13.983 回答
20

鉴于您最初的问题陈述,

我需要为我的程序使用列表,并且需要决定是使用 std::vector 还是 std::list。vector 的问题是没有 remove 方法,而 list 的问题是没有运算符 []。

无需创建自己的列表类(无论如何这不是明智的设计选择,因为std::list没有虚拟析构函数,这强烈表明它不打算用作基类)。

您仍然可以实现您想要使用std::vector的功能和std::remove功能。如果v是 a std::vector<T>,那么要删除 value value,您可以简单地编写:

#include <vector>
#include <algorithm>
T value = ...; // whatever
v.erase(std::remove(v.begin(), v.end(), value), v.end());
于 2008-12-14T12:07:45.867 回答
9

所有模板代码都应该放在头文件中。此填充修复链接问题(这是最简单的方法)。它发生的原因是因为编译器将每个源 (.cc) 文件与其他文件分开编译。另一方面,它需要知道它究竟需要创建什么代码(即模板中的 T 被替换为什么),除非程序员明确告诉它或在模板时包含所有代码,否则它没有其他方法可以知道它实例化发生。即当 mylist.cc 被编译时,它对 mylist 用户和需要创建什么代码一无所知。另一方面,如果 listuser.cc 被编译,并且所有 mylist 代码都存在,编译器会创建所需的 mylist 代码。您可以在此处或在 Stroustrup中阅读有关它的更多信息。

您的代码有问题,如果用户请求否定或太大(超过列表中的元素数量)怎么办。而且我没有看太多。

此外,我不知道你打算如何使用它,但你的 operator[] 是 O(N) 时间,这可能很容易导致 O(N*N) 循环......

于 2008-12-14T11:34:18.743 回答
6

向量具有可以删除元素的擦除方法。这还不够吗?

于 2008-12-14T11:34:13.313 回答
5

除了其他优秀的评论外,扩展标准容器的最佳方式不是派生,而是编写自由函数。例如,了解如何使用Boost 字符串算法来扩展std::string和其他字符串类。

于 2008-12-14T14:48:18.927 回答
1

您必须将所有模板代码移动到标题中。

于 2008-12-14T11:34:16.357 回答
1

明显的东西已经详细描述了:

但是您选择实施的方法?

  • 析构函数。
    • 不需要的编译器会为您生成。
  • operator[] 的两个不同版本毫无意义
    • 你也应该使用 std::list::size_type 作为索引
    • 除非您打算支持负索引。
  • 没有 const 版本的 operator[]
  • 如果你要实现 [] 你也应该做 at()
  • 您错过了构建列表的所有不同方式。
  • 容器应该在内部定义几种类型
于 2008-12-14T12:34:42.723 回答
0

无需调用 std::list 的析构函数,因为当自动为 myList 调用析构函数时,您已经从 std::list 派生了 std::list 析构函数。

于 2008-12-14T15:03:46.090 回答