【问题标题】:Inserting Objects into an array with dynamic memory (No vectors allowed) C++将对象插入到具有动态内存的数组中(不允许向量)C++
【发布时间】:2017-10-20 10:35:17
【问题描述】:

不允许使用向量专门用于这项学校作业。我发现的大多数答案都简单地将“您应该使用向量”作为投票最多的评论。虽然我很欣赏并理解这一点,但我只是被限制在这项任务中使用它们。

这是一个具有动态内存管理的 C++ 赋值,如下所示:

// property in header declaration
int numAnimals;
int capacity;
Animal** animals; 
void addAnimal(Animal *newAnimal);

// class implementation
capacity = 10;
numAnimals = 0;

animals = new Animal*[capacity];

void SampleClass::addAnimal(Animal *newAnimal)
{
  for (int i = 0; i < capacity; i++){
       if(animals[i]){
          // animal object already exists in array, move on
          i++;
       }else{
          animals[i] = newAnimal;
          numAnimals++;
          break;
       }
   }
}

animals 是指向指针的指针,在本例中是指向尚未创建的对象类型 Animal 的指针数组的指针。

使用“addAnimal”函数,我要做的是通过循环指针数组将动物对象添加到数组中,如果已经存在动物对象,则迭代到下一个索引。如果没有动物,则将该动物插入到数组中。

当我尝试访问数组中动物对象的成员函数时,抛出异常“读取访问冲突”

我的怀疑是因为: if(animals[i]) 可能没有做我认为它正在做的事情,通过调试器运行它我从来没有点击“else”部分,所以当方法完成时,数组仍然充满了没有设置为任何对象的指针.因此,当我尝试访问成员函数时,它属于一个不存在的对象。

那么,如果我的怀疑是正确的,那么以这种方式将新对象插入指针数组的最佳方法是什么?它们需要是指针,否则它会自动创建充满填充对象的数组,这不是我想要的。

我没有发布所有代码,因为我想让我的问题保持简短,抱歉我是 C++ 和 stackoverflow 的新手。是的,我知道之后要删除 [] 以清除内存。

感谢任何帮助,谢谢!

【问题讨论】:

  • 您已经拥有numAnimals。只需使用它:animals[numAnimals] = newAnimal; 不要搜索。
  • if(animals[i]) is 测试空指针,但是当您从 new 获取内存时,不能保证指针为空。无论如何,使用numAnimals 似乎是一个更好的主意。
  • 感谢@manni66,快速响应,在您提出时非常明显。 sp2danny 的答案也是我一直在寻找的,尽管我同意您的提示适用于我的用例。

标签: c++ arrays pointers memory-management


【解决方案1】:

由于在numAnimals 中,您保留了数组中当前动物指针数量的计数,因此您不需要for 循环来查找第一个可用插槽来添加新的动物指针(另请注意,假设如果您想使用代码中所示的for 循环,则必须注意将数组中的所有初始指针正确初始化为nullptr)。

你可以使用:

// Inside SampleClass::addAnimal(Animal *newAnimal):

animals[numAnimals] = newAnimal;
numAnimals++;

请注意,当您插入新动物时,请注意不要溢出您的数组容量。
因此,在插入新动物之前,您必须检查数组中是否有足够的空间,例如:

// Before inserting:
if (numAnimals == capacity) 
{
    // You ran out of capacity.
    //
    // 1. Allocate a new array with bigger capacity (e.g. 2X)
    // 2. Copy the content from the current array to the new one
    // 3. delete current array
}

附注:

是的,我知道之后要delete[]清除内存

请注意,如果您在animals 指针数组上调用delete[],您会释放此指针数组,但不是指向的Animal 对象。

【讨论】:

    【解决方案2】:
    int capacity = 10;
    Animal** animals = new Animal*[capacity];
    

    这分配了十个指针,除了它没有初始化, 这意味着您基本上拥有垃圾数据。

    if (animals[i])
    

    此测试针对nullptr 的这些指针之一,但既然你这样做了 没有初始化,不太可能是nullptr

    您需要在您之后添加一个循环传递以使数据无效 分配它:

    for(int i=0; i<capacity; ++i)
        animals[i] = nullptr;
    

    还有一个bug:

    if (animals[i]) {
        // animal object already exists in array, move on
        i++; // <- here
    

    这是错误的,你继续两次for (int i = 0; i &lt; capacity;i++)

    【讨论】:

      【解决方案3】:

      问题是“使用矢量”,尽管您的老师另有说明,但这是正确的做法。但是,如果您应该手动管理动态数组,那么您能做的最好的事情就是将所有脏内存内容封装在 class 中,然后编写自己的替换 std::vector。即为了避免动态分配遍布你的代码(特别是在应该处理Animals 并且不应该关心手动分配内存等的地方)你应该写一个class 来做到这一点(别无其他) 并提供更好的界面。我只能在这里概述这个想法:

      template <typename T> 
      class my_vector {
          private:
              T* data;
              size_t size;
              size_t capacity;
          public:
              void push_back(const T& t);
              size_t size();
              T& operator[](size_t index);
              void resize(size_t size);
              //... etc...
      };
      

      【讨论】:

      • “使用std::vector ...是正确的做法”这取决于“它”是什么。如果“它”正在编写可维护的生产代码,那么我同意。如果“它”正在试验指针以便您了解动态内存分配的工作原理,那么std::vector 并没有多大帮助。
      • @ArthurTacca thx 指出这一点,我的意思是“使用矢量”。即使使用类似矢量的类来试验指针也是“方式”恕我直言。如果不允许使用std::vector,那么恕我直言,应该自己编写替换
      猜你喜欢
      • 1970-01-01
      • 2019-12-04
      • 1970-01-01
      • 2021-05-05
      • 2017-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      相关资源
      最近更新 更多