我对在C ++中处理一个对象数组感到困惑,因为我似乎无法找到有关它们如何传递的信息(引用或值)以及它们如何存储在数组中。
我希望对象数组是指向该对象类型的指针数组,但我没有在任何地方找到它。它们是指针,还是对象本身会在数组的内存中布局?
在下面的示例中,自定义类myClass包含一个字符串(这会使它具有可变大小,或者字符串对象是否包含指向字符串的指针,因此占用一定量的空间。我尝试创建一个myContainer中的myClass对象的动态数组。在myContainer.addObject()方法中,我尝试创建一个更大的数组,将所有对象与一个新对象一起复制到其中,然后删除旧对象。我一点也不自信我正在用我的析构师正确地清理我的记忆 - 我可以在这方面做些什么改进?
class myClass
{
private:
string myName;
unsigned short myAmount;
public:
myClass(string name, unsigned short amount)
{
myName = name;
myAmount = amount;
}
//Do I need a destructor here? I don't think so because I don't do any
// dynamic memory allocation within this class
};
class myContainer
{
int numObjects;
myClass * myObjects;
public:
myContainer()
{
numObjects = 0;
}
~myContainer()
{
//Is this sufficient?
//Or do I need to iterate through myObjects and delete each
// individually?
delete [] myObjects;
}
void addObject(string name, unsigned short amount)
{
myClass newObject = new myClass(name, amount);
myClass * tempObjects;
tempObjects = new myClass[numObjects+1];
for (int i=0; i<numObjects; i++)
tempObjects[i] = myObjects[i]);
tempObjects[numObjects] = newObject;
numObjects++;
delete newObject;
//Will this delete all my objects? I think it won't.
//I'm just trying to delete the old array, and have the new array hold
// all the objects plus the new object.
delete [] myObjects;
myObjects = tempObjects;
}
};
答案 0 :(得分:3)
不,动态数组不是指向该类型的指针数组 - 它是指向第一个元素的指针。元素在内存中连续布局,并在数组delete[]
时被销毁。
因此,您的释放看起来很好 - 您创建了myClass
个对象的动态数组,因此您不必单独delete
它们。如果你有一个指向(动态分配的)对象的指针数组,你只需要这样做。
但有两个明确的错误:
tempObjects[numObjects] = newObject; // assign a myClass pointer to a myClass instance?
这应该是例如:
tempObjects[numObjects] = myClass(name, amount);
此外,myObjects
永远不会被初始化,这意味着它包含垃圾,解除引用/使用它会导致未定义的行为。
最后,除非您出于学习目的而这样做,否则只需使用像std::vector
这样的容器来为您完成所有工作。
答案 1 :(得分:3)
C ++中的数组是在内存中布置的对象数组。 例如在:
struct pair {
int x; int y;
};
...
pair array[10];
数组中的每个项目的大小都是两个整数。 如果你想要一个指针数组,你可以简单地声明一个:
pair* array_of_pointers[10];
字符串对象具有指向字符串的可变大小部分的指针。所以他们很安全。 事实上,他们是这里的重要教训。使用字符串类来避免过多的内存处理,可以使用vector类来避免处理动态数组的所有麻烦。
对于你正在做这个练习的情况。以下是一些问题:
newObject
需要在本地分配,而不需要new
。这将使代码正确(因为newObject
不是指针而new
返回指针)并且还将为您省去显式处理内存的麻烦。 (在更高级的说明中,这使得代码异常在另一个位置安全)
永远不会初始化myObject
。并且您不在构造函数中使用初始化列表。构造函数应如下所示:
myContainer() : numObjects(0), myObjects(NULL)
{
}
代码中的析构函数完全符合它们的要求。
答案 2 :(得分:1)
我希望对象数组是指向该对象类型的指针数组,但我没有在任何地方找到它。它们是指针,还是对象本身会在数组的内存中布局?
数组将由对象本身组成。如果你想拥有一个指针数组,你必须声明:
myClass ** tempObjects;
tempObjects = new myClass*[numObjects+1];
我假设你已经习惯了C#或Java?在这些语言中,对象只能在堆上分配,并且始终通过引用来访问。它可以在C ++中实现,但在C ++中,您也可以将对象直接放在堆栈上,或直接构造对象本身的数组。
在下面的示例中,自定义类myClass包含一个字符串(这会使它变为可变大小,或者字符串对象是否包含指向字符串的指针,因此占用一定量的空间?
第二个:字符串对象本身的大小是常量,但是有一个指向从堆分配的动态大小缓冲区的指针。
我认为解除分配看起来很好。代码可以通过各种方式更有效地编写,但看起来是正确的。
答案 3 :(得分:0)
尝试测试它,看看会发生什么(是的,这可能是编译器特定的,但仍然)... 您可以尝试向myClass添加自定义析构函数(即使您不需要),在调用时递增“全局”计数器,然后在删除数组后打印计数器。
我希望调用每个对象的析构函数。请注意,对象通常存储在“按指针”中,以允许将继承的对象放入数组中(避免“切片”)。