【问题标题】:Copy Constructor and Destructor with a Dynamic Array使用动态数组复制构造函数和析构函数
【发布时间】:2018-09-10 00:16:45
【问题描述】:

我一直在从事一个项目,我应该在该项目中使用动态数组重新创建函数的基础。该程序应该有一个默认构造函数,它创建一个大小为 2 的数组,并且“向量”的大小为 0,直到将更多值添加到向量类中,命名为 DynArray。当数组已满时尝试 .push_back 进入向量时,我的程序应该制作一个容量为 2 倍的数组的新副本,并删除旧数组。这是我到目前为止所拥有的,我正在努力弄清楚应该如何设置复制构造函数以使其正常工作。

我一直在努力获取 push_back 和复制构造函数之间跳跃 当我同时撞到墙上时,工作正常。

#include <iostream>
using namespace std;

class DynArray
{
   public:
      DynArray();
      DynArray(const DynArry& origClass);
      ~DynArray();
      int capacity();
      int size();
      void push_back(int newNum);
      int at(int atNum);

   private:
      int arraySize;
      int arrayCapacity;
      int newNum;
      int pushCounter;
      int atNum;
      int i;
      int arrayVector [];
};


DynArray::DynArray() // default constructor, creates array with no elements and capacity 2
{
   int* arrayVector = new int[2];
   arrayCapacity = 2;
   arraySize = 0;
   pushCounter = 0; // used for push_back, increments through array every time a new number is added with push_back
   return;
}

DynArray::DynArray(const DynArray& origClass) // copy constructor
{
   cout << "Copy Constructor Called." << endl;
   int* arrayVector = new int[2];
   *arrayVector = *(origClass.arrayVector)

   return;
}

void DynArray::push_back(int newNum)
{
   if (arraySize == arrayCapacity) // if the capacity is the same as the current size, make a new array with twice the capacity, copy over values, delete the old array
   {
      arrayCapacity = arrayCapacity * 2;
      int* newarrayVector = new int[arrayCapacity];
      for (i = 0; i < arraySize; ++i)
      {
         *newarrayVector [i] = arrayVector[i];
      }      
   arrayVector [pushCounter] = newNum; // push value to the next open value in the array
   ++arraySize; // increment so next push_back uses the following value
   ++pushCounter;
}

【问题讨论】:

  • 将复制构造函数中的大小设置为所需的大小。新的 int[orgClass.arrayCapacity]
  • 复制构造函数需要复制整个数组,就像您的push_back 函数在分配新内存时所做的那样。此外,您可以从类声明中删除newNum,它是传递给您的函数的参数,不需要在那里声明。删除pushCounter 并使用arraySize
  • 未来问题:没有赋值运算符。这打破了三法则,可以真正击中它的痛处。
  • 这个问题目前的措辞基本上意味着您正在要求某人为您编写代码。更具体地说明你为什么挣扎。此外,您的代码中存在很多问题。 pushCounter 没有用,因为它与 arraySize 做的事情完全相同。您有一个名为 arrayVector 的成员,它存储指向动态数组的指针,但是您随后在构造函数和 push_back 函数中声明了具有相同名称的局部变量。您还应该了解构造函数成员初始化列表,而不是为成员变量分配东西。
  • 为什么你不能分配一个新数组并复制每个元素呢? newNumatNum 是成员函数参数,而不是类成员。

标签: c++ constructor destructor copy-constructor


【解决方案1】:

您的复制构造函数应该复制传递给它的对象。

相反,它会这样做;

DynArray::DynArray(const DynArray& origClass) // copy constructor
{
    cout << "Copy Constructor Called." << endl;
    int* arrayVector = new int[2];
    *arrayVector = *(origClass.arrayVector);   // missing ; added here

    return;
}

忽略cout的输出,两个明显的问题是arrayVector动态分配了两个元素,而不管origClass.arrayVector中有多少元素。

语句int *arrayVector = *(origClass.arrayVector) 也根本不复制数组。

  • 首先,它创建一个名为 arrayVector 的指针(尽管名称相同,但它与 DynArray 的成员无关)。
  • 然后它复制origClass.arrayVector第一个元素(a 单个int) 到arrayVector第一个元素。所以它是 功能上等同于arrayVector[0] = origClass.arrayVector[0]。这就是指针的工作方式。
  • 最后,当构造函数返回时,声明的arrayVector 将不复存在,因为 if 是构造函数主体的局部变量。结果是动态分配的内存被泄露(没有变量或DynArray 类的成员完全引用它,因此在标准 C++ 中无法在后续代码中找到该内存)。

最后,您的复制构造函数不会复制origClass 的任何其他成员(arraySizearrayCapacitynewNumpushCounteratNumi) 到正在构造的新对象。

相反,您(通常)需要做的是复制所有成员,而不仅仅是其中一个。而且,如果要复制的成员之一是动态分配的数组 - 如您的情况 - 构造函数需要首先构造一个新数组,然后将所有元素复制到其中 - 一次一个,以某种形式的循环。

例如,你可以这样做

DynArray::DynArray(const DynArray& origClass) // copy constructor
{
    arrayVector = new int[origClass.arrayCapacity];

这实际上修改了DynaArrayarrayVector 成员(而不是声明一个局部变量)。它还使该指针指向与origClass 中大小相同的动态分配数组。

这还没有从origClass.arrayVector 复制数据。正如我上面提到的,这不能使用*arrayVector = *(origClass.arrayVector) 来完成。相反,构造函数需要这样做

   for (int i = 0; i < origClass.arrayCapacity; ++i)
       arrayVector[i] = origClass.arrayVector[i];

此步骤对于确保复制origClass.arrayVector 的所有元素至关重要。这是如何完成的(例如使用指针语法而不是数组语法),但上面的就足够了。

那么就需要从origClass复制所有其他成员。

   arraySize = origClass.arraySize;
   arrayCapacity = origClass.arrayCapacity;
   newNum = origClass.newNum;
   pushCounter = origClass.pushCounter;
   atNum = origClass.atNum;
   i = origClass.i;

}   // the body of the constructor ends here.

顺便说一句,让我感到震惊的是,你给你的DynArray 提供了一些它不需要的成员。其中一些成员仅在特定成员函数(例如循环计数器)中用作临时对象。这样做意味着DynArray 的每个实例都有自己的这些变量的副本。这是不必要的——它们最好是局部变量,在需要它们的每个函数中声明。

现在,上述方法(在某种程度上)可以工作,但需要改进。在可能的情况下,通常最好在构造函数中使用初始化器,并且让构造器主体只执行初始化器中无法完成的事情。这样做有很多好处,但你可以做一些功课来找出它们是什么。

因此,我最终会将复制构造函数实现为

DynArray::DynArray(const DynArray& origClass) :  // initialiser list begins here
        arrayVector(new int[origClass.arrayCapacity]),
        arraySize(origClass.arraySize),
        arrayCapacity(origClass.arrayCapacity),
        newNum(origClass.newNum), 
        pushCounter(origClass.pushCounter),
        atNum(origClass.atNum),
        i(origClass.i)
{
     // body of constructor starts here

     for (int i = 0; i < origClass.arrayCapacity; ++i)
         arrayVector[i] = origClass.arrayVector[i];
}

尽管我之前除了你有不必要的类成员之外,这里的初始化列表仍然复制你的所有 DynArray 成员。

请注意,复制数组元素的循环在构造函数的主体中,因为这种事情在初始化列表中不容易完成。

还要注意变量i(构造函数主体中的循环计数器)与名为iDynArray 的成员没有关系。

最后是DynArray的成员

int arrayVector []; 

最好将其声明为指针。它实际上不是一个数组。

int *arrayVector; 

【讨论】:

    【解决方案2】:

    您的复制构造函数可以访问它正在复制的对象的私有成员,因此它应该非常类似于您的 resize 方法。有快捷方式(memcpy、std::copy),但最好学习如何使用循环。

    所以,列出你遇到的小问题:

    • 在复制构造函数中,将大小设置为与原始对象相同的大小。 (不过,您可能会将其缩小为 arraySize)。
    • 使用循环或批量复制功能 (memcpy) 复制所有元素
    • 您的 push_back 方法中缺少一个 }
    • pushCounter 始终与 arraySize 完全相同。两者都不需要
    • i 应该是局部变量,而不是类成员。
    • 未使用类成员 atNum 和 newNum。

    【讨论】:

      【解决方案3】:

      几个明显的错误:

      DynArray(const DynArry& origClass);
                           ^
      

      这可能是一个错字。没有DynArry这样的类型。


       int arrayVector [];
      

      此成员声明格式不正确。您不允许拥有未指定大小的成员数组。由于您正在重新实现动态数组,因此这可能应该是一个指针,用于保存动态分配的数组的地址。指针声明如下:

        int* arrayVector;
      

      int* arrayVector = new int[2];
      

      这会将动态数组的地址存储在本地自动变量中。一旦构造函数结束,指针 - 自动 - 被破坏并且数组被泄露。您应该改为对this-&gt;arrayVector 进行更改。


      *arrayVector = *(origClass.arrayVector)
      

      这只会复制数组的第一个元素。复制构造函数可能应该复制所有元素。为此,您还应该构造一个与您从中复制的数组一样大的动态数组。

      此外,复制构造函数使许多成员未初始化(例如arraySize)。


       *newarrayVector [i] = arrayVector[i];
      

      这个表达式格式不正确。您不能对整数使用间接操作。您可能打算改为分配给数组元素:

      newarrayVector [i] = arrayVector[i];
      

      除此之外,您的重新分配会遇到与构造函数相同的问题。新数组只是在函数结束时泄漏,因为您没有将它存储在成员中。


      *arrayVector = *(origClass.arrayVector)
      
      return;
      

      这个表达式格式不正确。您可能忘记了分号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-13
        • 2013-04-17
        • 1970-01-01
        • 1970-01-01
        • 2013-07-07
        • 2015-12-05
        • 2017-02-08
        • 2021-03-22
        相关资源
        最近更新 更多