将对象插入到具有动态内存(不允许向量)C++的数组中



不允许使用Vectors专门用于此学校作业。我找到的大多数答案都只是简单地说"你应该使用向量",这是投票最多的评论。虽然我很感激并理解这一点,但我只是被限制在这项任务中使用它们。

这是一个具有动态内存管理的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"函数,我试图通过循环指针数组将动物对象添加到数组中,如果已经存在动物对象,则迭代到下一个索引。如果没有动物,则将该动物插入阵列中。

当我试图访问数组中动物对象的成员函数时,抛出了一个异常"读取访问违规">

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

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

我没有发布所有的代码,因为我想让我的问题简短,很抱歉,我是C++和stackoverflow的新手。是的,我知道删除[]以清除记忆。

感谢您的帮助!

由于在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对象。

int capacity = 10;
Animal** animals = new Animal*[capacity];

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

if (animals[i])

这是针对nullptr测试其中一个指针,但由于您这样做了没有初始化,它不太可能是nullptr

您需要添加一个循环传递,在您之后立即清空数据分配:

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

还有一个错误:

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

这是错误的,您上移动两次for (int i = 0; i < capacity;i++)

不管老师怎么说,"使用向量"是正确的方法。然而,如果你应该手动管理动态数组,那么你能做的最好的事情就是将所有脏内存封装在class中,并编写自己的std::vector替代品。也就是说,为了避免动态分配遍布代码(尤其是在那些应该处理Animal的地方,而不应该关心手动分配内存等),你应该编写一个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...
};

最新更新