Qix*_*Qix 3 c++ memory arrays initialization dynamic-allocation
所以这似乎是一个广泛回答的问题,但我更感兴趣的是两者之间究竟发生了什么不同的内部结构.
除了第二个示例不仅创建内存,而且还创建指向内存的指针的事实,当发生以下情况时,内存中会发生什么:
char a[5];
char b* = new char[5];
Run Code Online (Sandbox Code Playgroud)
与我提出这个问题的原因更直接相关,我该怎么做
const int len = 5;
char* c = new char[len];
Run Code Online (Sandbox Code Playgroud)
但不是
const int len = 5;
char d[len]; // Compiler error
Run Code Online (Sandbox Code Playgroud)
编辑应该提到我在VC++上遇到这个编译错误(去图......)
1>.\input.cpp(138) : error C2057: expected constant expression
1>.\input.cpp(138) : error C2466: cannot allocate an array of constant size 0
1>.\input.cpp(138) : error C2133: 'd' : unknown size
Run Code Online (Sandbox Code Playgroud)
编辑2:应该发布我正在使用的确切代码.当使用运行时值计算动态分配的数组的常量长度时,会产生此错误.
假设random(a,b)返回int介于a和之间b,
const int len1 = random(1,5);
char a[len1]; // Errors, since the value
// is not known at compile time (thanks to answers)
Run Code Online (Sandbox Code Playgroud)
而
const int len2 = 5;
char b[len2]; // Compiles just fine
Run Code Online (Sandbox Code Playgroud)
Jam*_*nze 16
不同之处在于阵列的寿命.如果你写:
char a[5];
Run Code Online (Sandbox Code Playgroud)
然后,数组具有其定义的块的生命周期(如果它在块作用域中定义),包含它的类对象(如果它在类范围中定义)或静态生命周期(如果它在命名空间范围内定义).如果你写:
char* b = new char[5];
Run Code Online (Sandbox Code Playgroud)
,那么数组有你需要的任何生命周期 - 你必须明确地终止它的生命周期:
delete [] b;
Run Code Online (Sandbox Code Playgroud)
关于你的上一个问题:
int const len = 5;
char d[len];
Run Code Online (Sandbox Code Playgroud)
是完全合法的,应该编译.哪里有区别:
int len = 5; // _not_ const
char d[len]; // illegal
char* e = new char[len]; // legal
Run Code Online (Sandbox Code Playgroud)
产生差异的原因主要是编译器技术和历史记录:在早期,编译器必须知道长度才能将数组创建为局部变量.
发生以下情况时,内存中会发生什么:
char a[5];
char *b = new char[5];
Run Code Online (Sandbox Code Playgroud)
假设一个典型但有点简化的C++实现,并且上面的代码出现在一个函数中:
char a[5];
Run Code Online (Sandbox Code Playgroud)
堆栈指针移动5个字节,以产生5个字节的空间.该名称a现在指的是5字节内存块.
char *b = new char[5];
Run Code Online (Sandbox Code Playgroud)
堆栈指针移动sizeof(char*),以便为其腾出空间b.调用一个函数,该函数消失并从称为"免费存储"的东西中分配5个字节,基本上它从操作系统获得的大块内存中分割出5个或更多字节,并进行一些簿记以确保何时你释放这些字节delete[],它们将可用于将来的重新分配.它返回分配的5个字节块的地址,该块存储在堆栈的空间中b.
第二个工作比第一个工作更多的原因是分配的对象new可以按任何顺序删除.局部变量(也称为"堆栈中的对象")总是以创建的相反顺序销毁,因此需要更少的簿记.在易于破坏的类型的情况下,实现可以仅在相反方向上将堆栈指针移动相同的距离.
为了删除我做的一些简化:堆栈指针实际上并没有为每个变量移动一次,可能它只在函数入口中移动一次,用于函数中的所有变量,在这种情况下,所需的空间至少是sizeof(char*) + 5.堆栈指针或各个变量可能存在对齐要求,这意味着它不会被所需的大小移动,而是被某些四舍五入的数量移动.实现(通常是优化器)可以消除未使用的变量,或者使用寄存器代替堆栈空间.可能还有其他一些我没有想过的事情.
const int len1 = random(1,5);
语言规则相当简单:数组的大小必须是常量表达式.如果const int变量在同一个TU中具有初始值设定项,并且初始值设定项是常量表达式,则变量名称可以用在常量表达式中.random(1,5)不是常量表达式,因此len1不能用于常量表达式.5是一个常数表达式,所以len2很好.
语言规则的用途是确保在编译时知道数组大小.所以移动堆栈,编译器可以发出指令等效于stack_pointer -= 5(其中stack_pointer会esp,或者r13,或其他).在这之后,它仍然"确切地"知道每个变量与堆栈指针的新值有什么抵消 - 与旧堆栈指针不同.可变堆栈分配会给实施带来更大负担.
| 归档时间: |
|
| 查看次数: |
19759 次 |
| 最近记录: |