C ++:自定义编码通用容器的潜在问题?

时间:2009-11-28 11:05:59

标签: c++

我无法使用STL和boost库,我必须用C ++编写自己的容器。以下代码在VC ++ 6中编译时没有错误。

我实际上没有对代码进行测试,但是担心这个通用容器是否适用于原始类型和非原始类型(如类)。复制构造函数和赋值运算符是否会出现任何潜在问题?

欢迎提出任何其他建议和意见。 :)

template <class T>  
class __declspec(dllexport) StdVector{

private:  
    int _pos;  
    int _size;  
    const T *_items;  

public:
    StdVector();
    StdVector(const StdVector &v);
    StdVector(int size);
    virtual ~StdVector();

    void Add(const T &item);
    void SetSize(int size);
    int GetSize();

    const T * Begin();
    const T * End();
    const T * ConstIterator();

    StdVector & operator=(const StdVector &v);
};

template <typename T>
StdVector<T>::StdVector() 
    : _pos(0), _size(0), _items(NULL){
}

template <typename T>
StdVector<T>::StdVector(const StdVector &v) 
    : _pos(0), _size(v.GetSize()), _items(new T[_size]){
    std::copy(v.Begin(), v.End(), Begin());
}

template <typename T>
StdVector<T>::StdVector(int size) 
    : _pos(0), _size(size), _items(new T[_size]){
}

template <typename T>
StdVector<T>::~StdVector(){
    if (_items != NULL)
        delete[] _items;
}

template <typename T>
void StdVector<T>::Add(const T &item){
    if (_pos == _size)
        throw new exception("Already at max size!!!");

    _items[_pos++] = item;
}

template <typename T>
void StdVector<T>::SetSize(int size){
    if (_items != NULL)
        delete[] _items;

    _pos = 0;
    _size = size;
    _items = new T[_size];
}

template <typename T>
int StdVector<T>::GetSize(){
    return _size;
}

template <typename T>
const T * StdVector<T>::Begin(){
    return _items;
}

template <typename T>
const T * StdVector<T>::End(){
    return _items + _pos;
}

template <typename T>
const T * StdVector<T>::ConstIterator(){
    return _items;
}

template <typename T>
StdVector<T> & StdVector<T>::operator=(const StdVector &v){
    if (this != &v){
        delete[] _items;
        std::copy(v.Begin(), v.End(), Begin());
    }

    return *this;
}

3 个答案:

答案 0 :(得分:5)

代码中有几件事。我仍然无法理解为什么在某些环境中禁止使用STL,当它经过彻底的测试并且相当便宜时(包括STL或任何其他模板化代码,你只编译你使用的部件)......这迫使人们重新发明轮子等等通常情况下,它会以粗糙的角落结束。

我会开始讨论STL被禁止的原因,并试图找出之前允许的库(如果决定性能,请考虑STL的Electronic Arts版本,如果他们不信任VC6 STL实现,请考虑STLPort )。在质量上开发接近STL的任何东西需要相当多的努力和知识。

现在到你的容器。首先,您要首先定义类要求,要对向量及其元素执行哪些操作。您的代码的限制是:

  • 存储的元素是常量:它们无法更改
  • 您无法从矢量中删除元素
  • 你的调整大小操作会破坏所有存储的元素,它不会非破坏性地增长/缩小(我不确定这是一个接口限制还是你提供的实现的问题)

您的代码有些特别之处:

  • 复制初始化和分配是不可能的:存储为const T*,因此在构建后无法更改。
  • 即使可能,分配也不是例外安全
  • 构建了向量中的所有元素(使用或不使用)(您为构建未使用的元素付费)
  • 所有单参数构造函数(但复制构造函数)应为explicit,以避免不必要的隐式转换。
  • GetSize和返回迭代器的方法应该是常量。

有些注意事项......你不能使用STL,但你可以使用属于STL的std::copy吗? STL的哪些部分超出限制?

答案 1 :(得分:4)

此默认值构造新对象并分配它们(或者,如果Begin()返回T*而不是const T*,请参阅dribeas的答案),如果你可能会更有效率使用原始存储并构建新对象。此外,由于GetSize()Begin()End()不是常量,因此无法在参数v上调用它们。

template <typename T>
StdVector<T>::StdVector(const StdVector &v) 
    : _pos(0), _size(v.GetSize()), _items(new T[_size]){
    std::copy(v.Begin(), v.End(), Begin());
}

if语句是多余的。 NULL指针上的delete[]没问题。此外,有任何意义,它是虚拟的吗?看起来这不是一个旨在派生出来的类。

template <typename T>
StdVector<T>::~StdVector(){
    if (_items != NULL)
            delete[] _items;
}

SetSize会销毁所有对象并创建新对象。这可能是“令人惊讶”的行为。此外,如果new抛出,则对象将指向释放的内存。再次,如果保护删除是多余的。

template <typename T>
void StdVector<T>::SetSize(int size){
    if (_items != NULL)
            delete[] _items;

    _pos = 0;
    _size = size;
    _items = new T[_size];
}

这有什么意义?它似乎与Begin相同。它甚至不是const方法。

template <typename T>
const T * StdVector<T>::ConstIterator(){
    return _items;
}

此尝试不会复制到刚刚删除的_items(再次查看有关Begin()返回const T*以及Begin()End()的要点不是const)?

template <typename T>
StdVector<T> & StdVector<T>::operator=(const StdVector &v){
    if (this != &v){
        delete[] _items;
        std::copy(v.Begin(), v.End(), Begin());
    }

    return *this;
}

这是exception课程的内容? std::exception没有带const char*的构造函数。您还应该抛出异常对象,而不是指向动态分配的异常对象的指针。清理由指针“抛出”的动态分配的异常几乎不可能做得很好。

template <typename T>
void StdVector<T>::Add(const T &item){
    if (_pos == _size)
            throw new exception("Already at max size!!!");

    _items[_pos++] = item;
}

答案 2 :(得分:2)

一些快速评论:

  1. 您应该编写单元测试。
  2. operator =将在std :: copy语句中崩溃
  3. 性能问题:新的T [_size]将导致默认构造函数被调用_size次。您也不应该要求T具有默认构造函数。
  4. SetSize的机制很奇怪。您应该尝试通过在需要时扩展大小来模拟std :: vector的行为。
  5. 额外奖励:您可以查看Stepanov的lecture notes(pdf)for Adob​​e。前几章是关于矢量类的设计。