1

我正在编写一个动态数组类。我包含了一个复制构造函数和 operator= 函数,以允许我将一个数组分配给另一个数组。当我将相同长度的数组相互分配时它可以工作,但是当它们具有不同的长度时,我会收到编译器内存警告和/或代码炸弹而不执行,具体取决于左侧数组是否大于右侧数组,反之亦然。我有一个向数组插入值的函数,并认为问题可能出在此处(注意:我必须注释掉析构函数中的内存删除才能使代码运行)。

class Array
{
    private:
    int * ptr;
    int size; 
    int numElement;

public:
    Array();
    Array(const int*, int);
    Array(const Array&);
    ~Array();
    void setValueAtIndex(int, int);
    void insertValueAtEnd(int ); 
    int getArraySize();
    const Array& operator=(const Array& );  
};

#include "array.h"
#include <stdlib.h>
#include <iostream>
using namespace std;

Array::Array()
{
  size = 10;
  numElement = 0;
  ptr = new int[size];
  for (int i = 0; i < size; ++i)
  {
    ptr[i] = 0;
  }
}

Array::Array(const int * ptr_, int size_)
{
  size = size_;
  numElement = size;
  ptr = new int[numElement];
  for (int i = 0; i < size; ++i)
  {
    ptr[i] = ptr_[i];
  }
}

Array::Array(const Array& other)
{
  size = other.size;
  numElement = other.numElement;
  if (other.ptr)
  {    
      ptr = new int[numElement];
      for(int i = 0; i < size; ++i)
      {
        ptr[i] = other.ptr[i];
      }
      if(!ptr)
      {
        exit(EXIT_FAILURE);
      }
  }
  else ptr = 0;
}

Array::~Array()
{
  if(ptr)
  {
   //delete [] ptr;
   //ptr = 0;
  }
}

void Array::setValueAtIndex(int a, int b)
{
  if(b > size)
  {  
      exit(EXIT_FAILURE);
  }
  ptr[b] = a;
}

void Array::insertValueAtEnd(int insert)
{
  if(numElement == size)
  {
      size++;
  } 
  ptr[size-1] = insert;
  numElement++;
}

int Array::getArraySize()
{
  return size;
}

const Array& Array::operator=(const Array& other)
{    
    if(this != &other)
    {
     if (ptr)
     {
       delete [] ptr;
      ptr = 0;
     }
     numElement = other.numElement;
     size = other.size;
     if(other.ptr)
     {
       ptr = new int[numElement];
       for(int i = 0; i < size; ++i)
       {
         ptr[i] = other.ptr[i]; 
       }
     }
     else ptr = 0;
    }
    return *this;
}
4

2 回答 2

1

您的代码存在多个问题!从复制构造函数中的次要开始:如果new T[n]失败,则不返回0。相反,它会抛出异常。因此,您的测试if (!ptr)将永远无法完成。在您的代码中,无论如何都为时已晚,因为您已经使用了指针!

赋值运算符完全是乱码!使用自赋值检查通常很好地表明代码不是异常安全的(如果没有此检查自赋值真的无法工作)或者您正在针对罕见情况进行优化(希望您没有将对象分配给自己而不是分配给其他对象)。在您的情况下,检查表明代码(如果它正在运行)将不是异常安全的:您开始删除如果分配内存失败并抛出,您将无法取回的内存。可能导致您悲痛的主要错误是您分配了numElements对象(这似乎是数组中元素的数量,而不是其容量)但您复制了size对象(这似乎是可能可用元素的数量,即numElements < size)。作为旁注,我强烈建议您为其容器使用与标准 C++ 库相同的名称,即size()实际元素capacity()的数量和为其保留空间的元素的数量。

综上所述,实现赋值运算符的最佳方法是利用已经为复制构造函数和析构函数所做的工作:它们已经知道如何复制对象以及如何摆脱对象。执行此操作的方法如下所示:

Array& Array::operator= (Array other) {
    this->swap(other);
    return *this;
}
void Array::swap(Array& other) {
     std::swap(this->ptr, other.ptr);
     std::swap(this->size, other.size);
     std::swap(this->numElements, other.numElements);
}

这种方法要求还有一个函数swap()可以交换该类型的两个对象。然而,写起来通常是微不足道的:你只是std::swap()每个成员。

于 2013-09-15T11:50:58.500 回答
0

您的代码使用 insertValueAtEnd() 中断,因为它不会增加底层数组的大小。这个简单的测试用例让我崩溃了:

int realarr[] = { 1,2,3};
Array arr1(realarr, 3);
arr1.insertValueAtEnd(7);

您需要检查您是否已达到容量(称为大小),如果是,则增加底层存储。

我假设你正在实现一个动态数组?

只是一个风格问题,如果你愿意,你可以忽略。更常见的是使用 name_ 作为类数据成员并将 name 作为参数传入。

于 2013-09-15T12:03:00.997 回答