在“C++ 编程语言”一书中,Stroustrup 说:
“要释放由new分配的空间,delete和delete[]必须能够确定分配的对象的大小。这意味着使用new的标准实现分配的对象将比静态对象占用更多的空间。通常,一个word 用于保存对象的大小。
这意味着分配的每个对象new
的大小都位于堆中的某个位置。该位置是否已知,如果是,我如何访问它?
在“C++ 编程语言”一书中,Stroustrup 说:
“要释放由new分配的空间,delete和delete[]必须能够确定分配的对象的大小。这意味着使用new的标准实现分配的对象将比静态对象占用更多的空间。通常,一个word 用于保存对象的大小。
这意味着分配的每个对象new
的大小都位于堆中的某个位置。该位置是否已知,如果是,我如何访问它?
实际上,内存分配器的典型实现也存储了一些其他信息。
没有标准的方法来访问这些信息,实际上标准中也没有说明存储了什么信息(以字节为单位的大小、元素的数量及其大小、指向最后一个元素的指针等)。
编辑:如果你有对象的基地址和正确的类型,我怀疑分配的大小可以相对容易地找到(不一定“完全免费”)。但是,有几个问题:
为了说明这可能会出错,假设我们这样做:
size_t get_len_array(int *mem)
{
return allcoated_length(mem);
}
...
void func()
{
int *p = new int[100];
cout << get_len_array(p);
delete [] p;
}
void func2()
{
int buf[100];
cout << get_len_array(buf); // Ouch!
}
这意味着 new 分配的每个对象的大小都位于堆中的某个位置。该位置是否已知,如果是,我如何访问它?
并非如此,并非所有情况都需要这样做。为了简化推理,可能需要两个级别的大小。在语言级别,编译器需要知道要销毁什么。在分配器级别,分配器需要知道如何释放仅给定指针的内存。
在语言级别,只有数组版本new[]
并且delete[]
需要处理任意大小。当你用 分配时new
,你会得到一个带有对象类型的指针,并且该类型具有给定的大小。
要销毁对象,不需要大小。当 you 时delete
,要么指针指向正确的类型,要么指针的静态类型是基类,而析构函数是虚拟的。所有其他情况都是未定义的行为,因此可以忽略(任何事情都可能发生)。如果它是正确的类型,那么大小是已知的。如果它是具有虚拟析构函数的基类,则动态调度将找到最终的覆盖器,并且此时类型是已知的。
可能有不同的策略来管理它,例如在 Itanium C++ ABI 中使用的策略(由多个平台中的多个编译器使用,尽管不是 Visual Studio)例如为每种类型生成多达 3 个不同的析构函数,其中一个是一个版本关心释放内存,因此虽然delete ptr
定义为调用适当的析构函数然后释放内存,但在这个特定的 ABI 中delete ptr
调用了一个特殊的析构函数,它既销毁又释放内存。
当您使用new[]
指针的类型时,无论动态数组中的元素数量如何,该类型都是相同的,因此无法使用该类型来检索该信息。一个常见的实现是分配一个额外的整数值并在那里存储大小,然后是真实对象,然后返回一个指向第一个对象的指针。delete[]
然后将接收到的指针向后移动一个整数,读取元素的数量,为所有元素调用析构函数,然后释放内存(由分配器检索的指针,而不是给程序的指针)。仅当类型具有非平凡析构函数时才需要这样做,如果类型具有平凡析构函数,则实现不需要存储大小,您可以避免存储该数字。
在语言级别之外,真正的内存分配器(想想malloc
)需要知道分配了多少内存,以便可以释放相同的内存量。在某些情况下,可以通过以与存储new[]
数组大小相同的方式将元数据附加到内存缓冲区来完成,方法是获取更大的块,将元数据存储在那里并返回超出它的指针。然后释放器将撤消转换以获取元数据。
另一方面,这并不总是需要的。小尺寸分配器的常见实现是分配内存页面以形成池,然后从中获得小分配。为了提高效率,分配器只考虑几个不同的大小,并且不完全适合其中一个大小的分配被碰撞到下一个大小。例如,如果您请求 65 字节,分配器实际上可能会给您 128 字节(假设池为 64 和 128 字节)。因此,给定分配器管理的较大块之一,从它分配的所有指针都具有相同的大小。然后分配器可以找到从中分配指针的块并从中推断出大小。
当然,这都是 C++ 程序无法以标准可移植方式访问的所有实现细节,确切的实现不仅会因程序而异,还会因执行环境而异。如果您有兴趣了解信息是如何真正保存在您的环境中的,您也许可以找到这些信息,但在尝试将其用于学习目的之外的任何用途之前,我会三思而后行。
您不是直接删除对象,而是向delete
操作员发送指针。参考 C++
使用 delete 后跟一个指向最初用 new 分配的内存块的指针:
int * ps = new int; // allocate memory with new
. . . // use the memory
delete ps; // free memory with delete when done
这将删除 ps 指向的内存;它不会删除指针 ps 本身。例如,您可以重用 ps 来指向另一个新分配