int globalInt = 1;
int main(){
int* heapInt = new int(1);
}
globalInt 和 heapInt 有什么区别?我知道 heapInt 指向的是堆中,我知道 globalInt 进入一些全局数据存储,但是有什么区别呢?为什么要使用一个而不是另一个?
预先感谢您的任何帮助。
int globalInt = 1;
int main(){
int* heapInt = new int(1);
}
globalInt 和 heapInt 有什么区别?我知道 heapInt 指向的是堆中,我知道 globalInt 进入一些全局数据存储,但是有什么区别呢?为什么要使用一个而不是另一个?
预先感谢您的任何帮助。
全局变量具有静态存储持续时间。这意味着对象从程序开始到结束都存在。它在整个程序期间都存在。
使用int
new-expression 创建的具有动态存储持续时间。它的生命周期从 new-expression 开始,在你 do 时结束delete heapInt;
。
您可以将这两个存储持续时间视为频谱的两端。全局变量使您对其生命周期的控制最少,因为它始终存在。动态分配的对象为您提供最大的控制权,因为您可以在代码中的任何位置创建和销毁它。
还值得注意的是,全局变量有一个名称。这使得该名称在范围内的代码的所有部分都可以访问该对象。相反,要访问动态分配的对象,您需要获得指向它的指针。
全局变量通常被认为是不好的做法,因为它们将全局状态引入您的程序。也就是说,您可能有一个修改或使用全局变量的函数,而没有明确说明它在其接口中这样做。这意味着该函数可能有秘密的副作用,导致难以测试的不可预测和不可维护的代码。
另一方面,动态分配的对象通常是必要的,但应谨慎使用。确保对象的生命周期得到适当管理是很重要的。一种方法是使用RAII,其中对象仅在构造函数中动态分配,然后在析构函数中相应地销毁。另一种现代方法是避免完全自己进行内存管理,而是使用智能指针。
有两个主要区别 - 范围和生命周期。
您可以globalInt
在程序中的任何地方使用,而您heapInt
只能在main
.
全局的生命周期是从程序开始(好吧,因为main
无论如何都进入之前)到结束,而动态分配的生命周期在您启动时开始,在您启动时new
消失delete
。
只是为了烤你的面条,你是否也考虑过
int globalInt = 1;
int* globalHeapInt = new int(1);
int main() {
int* heapInt = new int(1);
}
回答为什么部分:在堆中存储任何东西都会产生指针的开销 - 4 或 8 个字节,具体取决于您要构建的位数。
诸如用于普通数据类型的 globalInt 之类的全局值被写入可执行文件的“数据段”,并在操作系统启动应用程序时以硬连线方式加载到进程中。
globalHeapInt 将加载 NULL 值,然后在编译器提供的一些秘密引导“pre-main”代码中,程序将不得不执行:
globalHeapInt = malloc(sizeof(int));
*globalHeapInt = 1;
在 64 位系统上,您现在使用(至少)12 个字节来存储一个 4 字节的值。
“heapInt”执行类似的操作,但指针存储在堆栈或寄存器中。
为什么要使用全局值?当您拥有有限的已知数据量时,将它们放在简单的全局变量中是有意义的。
因此,堆主要用于动态存储 - 当您事先不知道是否需要或需要多少时。例如,想象一个将书籍列表作为命令参数的程序:
// reserve memory for upto 1000 Books.
Book globalBooks[1000];
// or use the heap when we know how many we need.
int main(int argc, const char* argv[])
{
int numBooks = argc;
if ( numBooks < 1 ) {
printf("Screw you and your empty book list.\n");
exit(1);
}
Books* heapBooks = new Books(numBooks);
...
}
第一种形式只能处理 1000 本书,但它始终可以存储多达 1000 本书。第二种形式可以处理任意数量的书籍,直至进程可用的最大内存量。