类 - 具有动态大小的用户定义的智能阵列

时间:2015-07-13 16:25:38

标签: c++ arrays class memory-management operator-overloading

我正在编写以下数组(类),当此数组的索引大于此数组的大小时,该数组会增加大小。 我知道矢量,但必须是数组。守则如下:

#include <iostream>

using namespace std;

class Array {

public:
Array():_array(new float[0]), _size(0){};
~Array() {delete[] _array;}
friend ostream &operator<<(ostream&,const Array&);
float& operator[] (int index) 
{
  if(index>=_size)
  {
    float* NewArray=new float[index+1];
    for(int i=0;i<_size;++i) NewArray[i]=_array[i];
    for(int i=_size;i<index+1;++i) NewArray[i]=0; 
    delete[] _array;
    _array=NewArray;
    _size=index+1;
  }
  return _array[index];
}

private:
  float *_array; // pointer to array
  int _size; // current size of array
};

ostream &operator << ( ostream &out,  const Array& obj) // overloading operator<< to easily print array
{
  cout << "Array:\n\n";
  for (int i=0;i<obj._size;++i) 
  {
    cout << obj._array[i];
    if(i+1!=obj._size) cout << ", "; 
  }
  cout << ".\n";
  return out;
}

int main()
{
  Array CustomArray;
  CustomArray[2] = CustomArray[1] = CustomArray[0] = 3.14; // **here is the problem**
  cout << CustomArray << endl;
}

一切正常,0警告,0 valgrind错误,输出:

3.14, 3.14, 3.14.

我有以这种方式编写此代码(在main中):

CustomArray[0] = CustomArray[1] = CustomArray[2] = 3.14;

现在是3个valgrind错误: 地址(some_address)是8个空闲块中的4个字节,

,输出如下:0, 0, 3.14.

不幸的是,我必须编写此代码以第二种方式工作 (CustomArray[0] = CustomArray[1] = CustomArray[2] = 3.14;) 你们能帮忙吗?提前致谢

2 个答案:

答案 0 :(得分:2)

您需要通过使用包含对Array对象的引用和传递给operator[]的索引的代理类型来解决此问题。此代理类型将隐式转换为float并可从float分配,使访问(主要是 1 )透明。

在这种情况下,我们也违反了三条规则,并实现了复制赋值运算符,将一个数组元素的值赋给另一个数组元素,以便foo[0] = foo[1]按预期工作。

我们需要进行以下更改:

  1. 重命名现有的operator[]并将其设为私有;它只会被代理类型使用。
  2. 创建一个新的operator[],返回代理类型的值。
  3. 编写代理类型。
  4. Array的定义中更改1:

    friend class ArrayElement; // So that ArrayElement can use access()
    private:
    float& access(int index) 
    {
      if(index>=_size)
      {
        float* NewArray=new float[index+1];
        for(int i=0;i<_size;++i) NewArray[i]=_array[i];
        for(int i=_size;i<index+1;++i) NewArray[i]=0; 
        delete[] _array;
        _array=NewArray;
        _size=index+1;
      }
      return _array[index];
    }
    

    改变2:

    // Inside of Array
    public:
        ArrayElement operator[](int index);
    
    // Implementation outside of Array
    ArrayElement Array::operator[](int index) {
        return ArrayElement(*this, index);
    }
    

    改变3:

    class ArrayElement
    {
        friend class Array; // So that Array can use our private constructor
    
    private:
        ArrayElement(Array & array, int index) : array(array), index(index) { }
    
    public:
        // Allows "foo[1] = 2"
        ArrayElement const & operator=(float v) const {
            array.access(index) = v;
            return *this;
        }
    
        // Violation of the rule of three, but it makes sense in this case.
        // Allows "foo[1] = foo[2]"
        ArrayElement const & operator=(ArrayElement const & other) const {
            array.access(index) = other;
            return *this;
        }
    
        // Allows "float x = foo[1]"
        operator float() const {
            return array.access(index);
        }
    
    private:
        Array & array;
        int index;
    };
    

    (次要最终更改,您需要在ArrayElement的定义之前转发声明Array。)

    See this working example

    1 这种方法的一个注意事项是在数组访问中使用类型推断(C ++ 11中的auto):

    auto x = an_array[1];
    

    现在xArrayElement而不是float,当an_array[1]发生变化时,会发现其值会发生变化。尝试为x分配不同的浮点值也会更改an_array[1]中的值,因为x只是该值的代理。

    将此与std::vector的一般行为进行对比,其中auto x = a_vector[0]将导致x成为向量的元素类型,因此将保存存储在其中的值的独立副本矢量。

    但请注意,std::vector<bool>专门化完全遵循我在此处给出的方法(返回代理对象),因此it does have the same auto caveat!你可以把它作为这种方法的祝福。

答案 1 :(得分:0)

直接或间接使用std::vector。你的陈述

  

我知道矢量但它必须是数组。

没有意义。保证std::vector具有连续存储,这可能是“数组”的意思。对于实例v,您始终可以使用表达式&v[0]来获取数组的基址,并且从C ++ 11开始,更易于阅读的v.data()也可以正常工作。这意味着您可以使用vector进行任何需要数组“C风格”作为指针和大小的函数调用,例如qsort

如果你不能在Array::operator []中自动调整大小,那么就像你做的那样制作一个类包装器,但在内部使用std::vector 。这更简单,更安全。特别地,您的代码具有二次最坏情况性能,例如,以下将非常缓慢:

Array CustomArray;
for ( int i = 0; i < 1000000; ++i )
     CustomArray[i] = i;

std::vector旨在出现此问题。

使用std::deque可以轻松解决您提及的其他问题(使用引用失效),但deque没有连续存储。因此,对于std::vector,您仍然必须使用cdhowie所描述的代理。但是,我必须承认我不太明白为什么语法必须像那样,或者手动调用std::vector<float>::resize()有什么问题。