获取动态C样式数组的大小与使用delete[]的比较。矛盾 我读到C++中的任何地方都不可能从指向内存块的指针中获得一个动态数组的大小。

获取动态C样式数组的大小与使用delete[]的比较。矛盾 我读到C++中的任何地方都不可能从指向内存块的指针中获得一个动态数组的大小。,c++,arrays,heap,C++,Arrays,Heap,怎么可能无法仅从指针获取动态数组的大小,同时可以仅在指针上使用delete[]释放分配的所有内存,而无需指定数组大小 delete[]必须知道数组的大小,对吗?因此,这些信息一定存在于某个地方。不是吗 我的推理有什么错误?它是这样的-分配器或其背后的一些实现细节确切地知道块的大小 但这些信息并没有提供给您或程序的“代码层” 这门语言可以做到这一点吗?当然这可能是一个“不要为你没有使用的东西付费”的例子——记住这些信息是你的责任。毕竟,你知道你需要多少记忆!通常情况下,人们不希望某个号码的成本被传

怎么可能无法仅从指针获取动态数组的大小,同时可以仅在指针上使用
delete[]
释放分配的所有内存,而无需指定数组大小

delete[]
必须知道数组的大小,对吗?因此,这些信息一定存在于某个地方。不是吗


我的推理有什么错误?

它是这样的-分配器或其背后的一些实现细节确切地知道块的大小

但这些信息并没有提供给您或程序的“代码层”

这门语言可以做到这一点吗?当然这可能是一个“不要为你没有使用的东西付费”的例子——记住这些信息是你的责任。毕竟,你知道你需要多少记忆!通常情况下,人们不希望某个号码的成本被传递到调用堆栈中,而大多数情况下,他们并不需要这样做


有一些特定于平台的“扩展”可以满足您的需求,比如在Linux和Windows上,尽管这些扩展假定您的分配器使用了
malloc
,并且没有执行任何其他可能在最低级别扩展已分配块大小的魔法。我想说,如果您真的需要它,您最好自己跟踪它……或者使用向量。

这个答案仅适用于Microsoft Visual Studio

有一个名为msize的函数,它将返回指针的malloced/calloced/realloced大小

可以在malloc.h标题中找到,参数为:

size_t _msize(
   void *memblock
);

我不确定gcc中是否有类似的标准。可能应该有。

TL;DR操作员
delete[]
销毁对象并释放内存。销毁时需要信息N(“元素数量”)。释放时需要信息S(“已分配内存的大小”)。S始终被存储,并且可以由编译器扩展查询。仅当销毁对象需要调用析构函数时,才会存储N。如果存储了N,则其存储位置取决于实现


操作员
delete[]
必须做两件事:

a) 销毁对象(必要时调用析构函数)和

b) 释放内存

让我们首先讨论(de)分配,它 由许多编译器(如GCC)委托给C函数
malloc
free
。函数
malloc
将要分配的字节数作为参数并返回指针。函数
free
只需要一个指针;字节数不是必需的。这意味着内存分配函数必须跟踪分配了多少字节。可以使用一个函数来查询分配了多少字节(在Linux中可以使用,在Windows中可以使用)这不是您想要的,因为它告诉您数组的大小,但告诉您分配的内存量。由于
malloc
不一定能提供您所需的内存,因此您无法根据
malloc\u可用大小
的结果计算数组大小:

#include <iostream>
#include <malloc.h>

int main()
{
    std::cout << malloc_usable_size(malloc(42)) << std::endl;
}
此代码为您提供42:

仅针对协议:这是未定义的行为,但在当前版本的GCC中它可以工作

因此,您可能会问自己,为什么没有查询此信息的函数。答案是GCC并不总是存储这些信息。在某些情况下,销毁对象可能是一个不可操作的操作(编译器能够找到答案)。考虑下面的例子:

#include <iostream>

struct foo {
    char a;
    //~foo() {}
};

int main()
{
    foo * ptr = new foo[42];
    std::cout << *(((std::size_t*)ptr)-1) << std::endl;
}
#包括
结构foo{
字符a;
//~foo(){}
};
int main()
{
foo*ptr=新的foo[42];

我认为这是三个因素综合的结果

  • C++有一种“你只为你使用的东西付费”的文化
  • C++最初是作为C的预处理器出现的,因此必须在C提供的基础上构建
  • C++是世界上移植最广泛的语言之一。现有端口难以使用的特性不太可能被添加
  • C允许程序员在不指定要释放的内存块大小的情况下释放内存块,但不为程序员提供任何访问分配大小的标准方法。此外,实际分配的内存量可能远远大于程序员要求的内存量

    <>根据“你只为你使用的东西付费”的原则,C++实现对不同的类型执行<代码>新[]/COD>不同的类型。通常,如果需要的话,它们只存储大小,通常是因为类型有一个非平凡的析构函数。


    因此,虽然存储了足够的信息来释放内存块,但是很难定义一个明智的、可移植的API来访问该信息。根据数据类型和平台,实际请求的大小可能是可用的(对于C++实现必须存储的类型)只有实际分配的大小才是可用的(对于C++实现不必在底层内存管理器有扩展以获得分配的大小的平台上存储)的类型,或者大小可能根本不可用。(对于C++实现不必存储在无法访问底层内存管理器的信息的平台上的类型)。

    < P>如果<代码> DEL> []/COD>不必知道在调用时数组的大小,则整个参数会崩溃。
    在调用时不必知道数组的大小。它只需要
    #include <iostream>
    
    struct foo {
        char a;
        //~foo() {}
    };
    
    int main()
    {
        foo * ptr = new foo[42];
        std::cout << *(((std::size_t*)ptr)-1) << std::endl;
    }