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

Han*_*123 5 c++ arrays memory-management class 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;
}
Run Code Online (Sandbox Code Playgroud)

一切都好,0警告,0 valgrind错误,输出:

3.14, 3.14, 3.14.
Run Code Online (Sandbox Code Playgroud)

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

CustomArray[0] = CustomArray[1] = CustomArray[2] = 3.14;
Run Code Online (Sandbox Code Playgroud)

现在它是3个valgrind错误:地址(some_address)是一个大小为8的块中的4个字节,

和输出看起来像这样: 0, 0, 3.14.

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

cdh*_*wie 2

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

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

我们需要进行以下更改:

  1. 重命名现有的operator[]并将其设为私有;它只会被代理类型使用。
  2. 创建一个新的operator[]返回代理类型的值。
  3. 写入代理类型。

更改 1,在 的Array定义中:

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];
}
Run Code Online (Sandbox Code Playgroud)

变化2:

// Inside of Array
public:
    ArrayElement operator[](int index);

// Implementation outside of Array
ArrayElement Array::operator[](int index) {
    return ArrayElement(*this, index);
}
Run Code Online (Sandbox Code Playgroud)

变化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;
};
Run Code Online (Sandbox Code Playgroud)

(最后的小改动,您需要ArrayElement在 的定义之前转发声明Array。)

请参阅此工作示例


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

auto x = an_array[1];
Run Code Online (Sandbox Code Playgroud)

Nowx是 anArrayElement而不是 a float,当变化时,会观察到它的值发生变化an_array[1]。尝试分配不同的浮点值x也会更改该值an_array[1],因为x仅仅是该值的代理。

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

但请注意,std::vector<bool>专业化完全遵循我在这里给出的方法(返回代理对象),因此它确实有相同的auto警告!您可以将此视为对这种方法的祝福。