代码之家  ›  专栏  ›  技术社区  ›  Alexander Stolz

扩展std::list

  •  7
  • Alexander Stolz  · 技术社区  · 17 年前

    我需要为我的程序使用列表,并需要决定是使用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;
    }
    

    我可以编译它,但如果我尝试使用它,就会出现链接器错误。有什么想法吗?

    8 回复  |  直到 17 年前
        1
  •  52
  •   Glorfindel Doug L.    7 年前

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

    Container Choice
    (来源: adrinael.net )

        2
  •  21
  •   ChrisN    17 年前

    鉴于你最初的问题陈述,

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

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

    你仍然可以通过使用来实现你想要的东西 std::vector 以及 std::remove 功能。如果 v 是a std::vector<T> ,然后删除该值 value ,你可以简单地写:

    #include <vector>
    #include <algorithm>
    T value = ...; // whatever
    v.erase(std::remove(v.begin(), v.end(), value), v.end());
    
        3
  •  10
  •   Drakosha    17 年前

    所有模板代码都应该放在头文件中。此填充修复了链接问题(这是最简单的方法)。 发生这种情况的原因是编译器将每个源(.cc)文件与其他文件分开编译。另一方面,它需要知道它到底需要创建什么代码(即模板中的T被替换为什么),并且它没有其他方法来知道它,除非程序员在模板实例化发生时明确地告诉它或包括所有代码。也就是说,当mylist.cc被编译时,它对mylist用户和需要创建的代码一无所知。另一方面,如果编译了listuser.cc,并且所有mylist代码都存在,编译器将创建所需的mylist代码。你可以在 here 或者在Stroustrup。

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

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

        4
  •  6
  •   Sydius    17 年前

    矢量具有 erase method 这可以去除元素。这还不够吗?

        5
  •  5
  •   Nemanja Trifunovic    17 年前

    除了其他优秀的注释外,扩展标准容器的最佳方式不是派生,而是编写自由函数。例如,看看如何 Boost String Algorithms 可用于扩展 std::string 以及其他字符串类。

        6
  •  1
  •   mikea    17 年前

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

        7
  •  1
  •   Loki Astari    17 年前

    显而易见的事情已经详细描述过了:

    但是你选择实施的方法呢??

    • 破坏者。
      • 不需要的编译器将为您生成。
    • 运算符[]的两个不同版本毫无意义
      • 您还应该将std::list::size_type作为索引
      • 除非你打算支持负指数。
    • 运算符[]没有常量版本
    • 如果你要实现[],你也应该执行at()
    • 你错过了构建列表的所有不同方法。
    • 容器应在内部定义几种类型
        8
  •  0
  •   Qubeuc    17 年前

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