jar*_*auh 61 c++ dynamic-arrays
我知道在C++中无法获得动态创建的数组的大小,例如:
int* a;
a = new int[n];
Run Code Online (Sandbox Code Playgroud)
我想知道的是:为什么?人们是否在C++规范中忘记了这一点,还是有技术原因?
信息不是存储在某个地方吗?毕竟,命令
delete[] a;
Run Code Online (Sandbox Code Playgroud)
似乎知道它必须释放多少内存,所以在我看来,delete[]
有一些方法可以知道它的大小a
.
Mar*_*ica 38
这是"不为你不需要付出代价"的基本规则的后续行动.在您的示例delete[] a;
中不需要知道数组的大小,因为int没有析构函数.如果你写了:
std::string* a;
a = new std::string[n];
...
delete [] a;
Run Code Online (Sandbox Code Playgroud)
然后delete
必须调用析构函数(并且需要知道要调用多少) - 在这种情况下new
必须保存该计数.然而,由于它并不需要被保存在所有场合,Bjarne的决定不给访问它.
(事后看来,我认为这是一个错误...)
即使int
当然,事情有了解的分配内存的大小,但是:
为了对齐和方便的原因,许多分配器将大小四舍五入到一些方便的倍数(比如64字节).分配器知道一个块长64个字节 - 但它不知道是因为n
是1还是16.
C++运行时库可能无法访问已分配块的大小.例如,new
并且delete
正在使用malloc
和free
引擎盖下,那么C++库无法知道返回的块的大小malloc
.(一般是当然,new
而且malloc
是同一个库的两个组成部分-但并不总是)
mol*_*ilo 13
一个基本原因是指向动态分配的数组的第一个元素的T
指针和指向任何其他数组的指针之间没有区别T
.
考虑一个虚构函数,它返回指针指向的元素数.
我们称之为"大小".
听起来真的很好,对吧?
如果不是因为所有指针都是相同的:
char* p = new char[10];
size_t ps = size(p+1); // What?
char a[10] = {0};
size_t as = size(a); // Hmm...
size_t bs = size(a + 1); // Wut?
char i = 0;
size_t is = size(&i); // OK?
Run Code Online (Sandbox Code Playgroud)
你可以说第一个应该是9
,第二个10
,第三个9
,也可以是最后一个1
,但要完成这个,你需要在每个对象上添加一个"大小标签" .
A char
将需要64位计算机上的128位存储(因为对齐).这比必要的多16倍.
(上面,十个字符的数组a
至少需要168个字节.)
这可能很方便,但也是不可接受的昂贵.
当然,如果参数确实是默认情况下动态分配的第一个元素的指针,那么你当然可以想象一个只有良好定义的版本operator new
,但这并不像人们想象的那么有用.
小智 2
您经常会发现内存管理器只会分配一定倍数的空间,例如 64 字节。
因此,您可能会请求 new int[4],即 16 个字节,但内存管理器将为您的请求分配 64 个字节。要释放该内存,它不需要知道您请求了多少内存,只需知道它已为您分配了一个 64 字节的块。
下一个问题可能是,它不能存储请求的大小吗?这是一项额外的开销,并不是每个人都愿意为此付出代价。例如,Arduino Uno 只有 2k RAM,在这种情况下,每个分配的 4 个字节突然变得很重要。
如果您需要该功能,那么您可以使用 std::vector (或等效语言),或者使用更高级的语言。C/C++ 的设计目的是让您能够以尽可能少的开销进行工作,这就是一个例子。