C++ 为什么我们可以删除数组,但不知道C/C++;?

C++ 为什么我们可以删除数组,但不知道C/C++;?,c++,c,arrays,C++,C,Arrays,为什么我们可以删除动态分配的数组,但却无法找出它们有多少个元素?我们不能将内存位置的大小除以每个对象的大小吗?内存分配器会记住分配的大小,但不会给用户。C中的代码为“ MalOC ”,C++中使用 < < /代码> .< 无法获取“内存位置的大小”。如果你这样做 int *a = new int[N]; std::cout << sizeof(a); int*a=新的int[N]; 有两件事不利于它吗 首先,数组和指针是可互换的——数组对其长度没有任何额外的理解。(*所有试图对数组

为什么我们可以删除动态分配的数组,但却无法找出它们有多少个元素?我们不能将内存位置的大小除以每个对象的大小吗?

内存分配器会记住分配的大小,但不会给用户。C中的代码为“<代码> MalOC ”,C++中使用<代码> < < /代码> .< 无法获取“内存位置的大小”。如果你这样做

int *a = new int[N];
std::cout << sizeof(a);
int*a=新的int[N];

有两件事不利于它吗

  • 首先,数组和指针是可互换的——数组对其长度没有任何额外的理解。(*所有试图对数组和指针之间的根本区别发表评论的聪明评论员都应该注意,在这一点上,这些都没有任何区别;)*)

  • 其次,因为知道分配的大小是堆的工作,堆不公开任何发现分配大小的标准方法

  • 然而,Symbian确实有一个
    AllocSize()
    函数,您可以从中得出数组中有多少个元素。然而,有时分配比请求的要大,因为它管理按字对齐的块的内存。C++中的

    ,都…

    • 新的、新的[]或malloc调用请求的大小(字节),以及
    • 在新[]动态分配中请求的数组元素数
    …是标准不要求以编程方式提供的实现细节,即使内存分配库必须记住前者,编译器必须记住后者,以便能够在正确的元素数上调用析构函数

    有时,编译器可能会看到大小恒定的分配,并能够将其与相应的释放可靠关联,因此它可以生成为这些编译时已知值(例如内联和循环展开)定制的代码,但使用非常复杂(以及在处理外部输入时)编译器可能需要在运行时存储和检索#元素:例如,在为数组内容返回的地址之前或之后,可能会为#元素计数器放置足够的空间,delete[]知道此约定。实际上,编译器可能会选择总是在运行时处理这个问题,这仅仅是为了一致性带来的简单性。还存在其他运行时可能性:例如#元素可以从特定内存池的某些细节中派生出来,从该内存池中可以结合对象大小来满足分配

    该标准不提供编程访问,以确保实现在可能使用的优化(速度和/或空间)中不受限制


    (内存位置的大小可能大于所请求的元素数所需的精确大小——内存分配库所记忆的大小,它可以是独立于C++编译器的黑盒库)。

    您可以很容易地让类跟踪分配计数。

    我们不知道长度的原因是因为它一直是一个实现细节(afaik)。编译器知道元素的对齐方式,abi也会影响它的实现方式

    例如,安腾64 abi将cookie(元素计数)存储在分配的前导字节(特别是非POD)中,然后根据需要填充到对象的自然对齐中。然后(从
    new[]
    )返回第一个可用元素的地址,而不是实际分配的地址。因此,这里涉及到大量不可移动的簿记

    包装器类是管理这一点的简单方法

    编写分配器、重写object::new/delete和placement运算符,并查看它们是如何组合在一起的,这实际上是一个有趣的练习(尽管如果希望在生产代码中使用分配器,这不是一个特别简单的练习)

    简言之,我们不知道内存分配的大小,与使用包含指针和
    大小的自定义模板类相比,在多个平台上一致地计算分配大小(以及其他必要的变量)需要付出更多的努力

    此外,无法保证分配器准确分配了请求的字节数(因此,如果根据分配大小确定计数,则计数可能是错误的)。如果您通过malloc接口,您应该能够找到您的分配。。。但对于任何非琐碎的情况来说,这仍然不是非常有用、可移植或安全的

    更新:

    @默认情况下,创建自己的接口有很多原因。正如Tony提到的,
    std::vector
    是一个众所周知的实现。这种包装器的基础很简单(接口借用自
    std::vector

    /* holds an array of @a TValue objects which are created at construction and destroyed at destruction. interface borrows bits from std::vector */
    template<typename TValue>
    class t_array {
        t_array(const t_array&); // prohibited
        t_array operator=(const t_array&); // prohibited
        typedef t_array<TValue>This;
    public:
        typedef TValue value_type;
        typedef value_type* pointer;
        typedef const value_type* const_pointer;
        typedef value_type* const pointer_const;
        typedef const value_type* const const_pointer_const;
        typedef value_type& reference;
        typedef const value_type& const_reference;
    
        /** creates @a count objects, using the default ctor */
        t_array(const size_t& count) : d_objects(new value_type[count]), d_count(count) {
            assert(this->d_objects);
            assert(this->d_count);
        }
    
        /** this owns @a objects */
        t_array(pointer_const objects, const size_t& count) : d_objects(objects), d_count(count) {
            assert(this->d_objects);
            assert(this->d_count);
        }
    
        ~ t_array() {
            delete[] this->d_objects;
        }
    
        const size_t& size() const {
            return this->d_count;
        }
    
        bool empty() const {
            return 0 == this->size();
        }
    
        /* element access */
        reference at(const size_t& idx) {
            assert(idx < this->size());
            return this->d_objects[idx];
        }
    
        const_reference at(const size_t& idx) const {
            assert(idx < this->size());
            return this->d_objects[idx];
        }
    
        reference operator[](const size_t& idx) {
            assert(idx < this->size());
            return this->d_objects[idx];
        }
    
        const_reference operator[](const size_t& idx) const {
            assert(idx < this->size());
            return this->d_objects[idx];
        }
    
        pointer data() {
            return this->d_objects;
        }
    
        const_pointer data() const {
            return this->d_objects;
        }
    
    private:
        pointer_const d_objects;
        const size_t d_count;
    };
    
    /*保存@a TValue对象数组,这些对象在构造时创建,在销毁时销毁。接口从std::vector借用位*/
    模板
    类t_数组{
    t_数组(const t_数组&);//禁止
    t_数组运算符=(常量t_数组&);//禁止
    typedef t_arrayThis;
    公众:
    typedef t值类型;
    typedef值\u type*指针;
    类型定义常量值\u类型*常量指针;
    类型定义值\u类型*常量指针\u常量;
    类型定义常量值\u类型*常量指针\u常量;
    类型定义值\u类型和参考;
    类型定义常量值\u类型和常量参考;
    /**使用默认的ctor创建@a count对象*/
    t_数组(常量大小t&count):d_对象(新值类型[count]),d_计数(count){
    断言(此->d_对象);
    断言(此->d_计数);
    }
    /**它拥有@a对象*/
    t_数组(指针常数对象、常数大小和计数):d_对象(对象)、d_计数(计数){
    断言(此->d_对象);
    断言(此->d_计数);
    }
    ~t_数组()