【发布时间】:2011-02-14 16:13:56
【问题描述】:
我注意到有两种方法可以创建 C++ 对象:
BTree *btree = new BTree;
和
BTree btree;
据我所知,唯一的区别在于类对象的访问方式(. vs. -> 运算符),当使用第一种方式时,私有整数被初始化为 0。
哪种方式更好,有什么区别?
您如何知道何时使用其中一种?
【问题讨论】:
我注意到有两种方法可以创建 C++ 对象:
BTree *btree = new BTree;
和
BTree btree;
据我所知,唯一的区别在于类对象的访问方式(. vs. -> 运算符),当使用第一种方式时,私有整数被初始化为 0。
哪种方式更好,有什么区别?
您如何知道何时使用其中一种?
【问题讨论】:
在选择堆栈或堆分配内存时,您需要深入了解两者之间的差异。
是的,堆栈内存具有在超出范围时自动释放的优点,尽管使用智能指针和堆分配也可以实现相同的目的。更重要的是发生这种情况的原因。
性能: 堆栈内存会自动清理,因为它涉及在内存超出范围时简单地移动堆栈指针。由于这个原因,堆栈内存的分配和释放比堆内存快得多。
内存寿命: 堆分配的内存在分配函数范围之外可用。堆栈不是。根据上面关于调整堆栈指针的推理,一旦内存被释放,它是空闲的并且很可能在下一次堆栈分配时被覆盖。
简而言之,在临时分配时使用堆栈内存,特别是在需要重复分配且性能很重要的情况下。当对象需要在分配方法之外存在时使用堆内存。
【讨论】:
这两种形式的另一个区别是为这些对象分配存储的时间。 BTree bTree; 形式命名静态分配,其分配在编译时完成——即编译器将在运行时为该对象在内存中安排内存空间。而BTree *pbTree = new BTree 的分配,所谓的动态分配——在运行时执行——即只有在运行程序到达这一点时才会分配内存。
在这种情况下,静态分配和动态分配之间的区别并不明显。考虑以下情况,您需要为整数数组分配内存空间,但元素的数量只能在运行时确定,即我们只能在程序开始执行后才能知道数组消耗的确切内存空间。
// in this function, we want to return a copy of the parameter array
int *array_cpy( int *arr, int num ){
int *copy = new int[ num ];
int i;
for( i = 0; i < num; i++ ){
copy[ i ] = arr[ i ];
}
return copy;
}
这里int copy[ num ]; 的定义不合适,一个原因是我上面所说的,另一个是copy 的生命周期超过了函数的寿命。然而,鉴于最近的语言规范允许 VLA,第二个原因是这个问题的关键。
【讨论】:
高级别的区别是对象生命周期。例如,如果您正在编写一个视频游戏,您将通过new 在堆上分配与怪物对应的对象。这样,怪物的底层对象就和怪物一样长,这在你编写程序时是不可知的。当玩家杀死怪物时,您的代码可以使用delete 销毁怪物对象。
另一方面,总分计数器可以使用另一种形式,因为您知道希望计数器保持多长时间(大概只要游戏正在运行!)。通过将该表单置于任何函数体之外的“全局范围”中,它将被静态分配,作为程序二进制本身的一部分。
最后,如果你在计算一个数组的总和,像这样:
int mysum(int* arr, int len) {
int sum = 0;
for (int i = 0; i < len; ++i) { sum += arr[i] }
return sum;
}
sum 变量在堆栈上分配,这基本上是您想要的:一个您不必显式解除分配的临时变量,并且仅在该函数实际运行时才存在。
【讨论】:
两个区别:
它们在内存的不同部分(堆与堆栈)创建对象
对象生命周期不同: 在第一种情况下,代码显式管理内存分配,还必须显式管理释放(使用 delete/delete[])。
在第二种情况下,对象在其封闭范围(方法、方法内的嵌套块或类)结束时自动释放
你使用哪一个主要取决于对象的生命周期(它是否应该比创建它的方法寿命更长)。
【讨论】:
void foo() { BTree* btree=new BTree; btree->DoSomething(); delete btree; }
new)本身不会被“释放”。例如,它的析构函数不会在程序结束时被调用。但是,对象使用的内存将返回给操作系统。在现代操作系统下运行的程序在退出后无法继续消耗内存,无论它泄漏得多么严重。
第一种形式在堆上创建对象,而第二种形式在堆栈上创建对象。
第二个 from 将在函数运行完成后销毁。 第一个将保持活动状态,直到被明确删除。
如果您只想在当前范围内使用对象,则第二种形式是最好的。您无需担心摆脱它,因为它会为您完成。另请注意,如果在堆栈上创建了类,则某些库将不起作用。
如果对象的寿命比函数长,那么新形式是更好的选择。
【讨论】:
嗯,它们被存储在完全不同的内存区域中。
这是一个很好的阅读。 Heap and Stack
【讨论】:
BTree btree; 语句在静态内存中创建对象,这很有意义,尤其是在内存受限的环境中(所有那些自动内存管理的语言,如 Java cough似乎让我们失明..)。