【问题标题】:Where does c++ store the size of fix sized array?c++ 在哪里存储固定大小数组的大小?
【发布时间】:2017-09-22 16:39:46
【问题描述】:

这个问题是Declaring array of int的跟进

考虑以下程序:

#include <iostream>
#include <string>

int main()
{
  int x[10];
  std::cout << sizeof(x) << std::endl;
  int * y = new int [10];
  std::cout << sizeof(y) << std::endl;
  //delete [] y;
}

sizeof(x) 打印 40(总大小),sizeof(y) 打印 8(指针大小)

它看起来很有趣,对我来说int x[10]y 没有什么不同,只是它位于堆栈中。 c++ 究竟在哪里存储了x 的大小? c++ 是否从堆栈中获取它?还是将固定大小的数组视为内部具有大小的结构?

【问题讨论】:

  • 它根本不存储它。如果您需要,请改用std::array&lt;int,10&gt;
  • 它不(存储大小),编译器知道x 的完整类型,其中包括数组的大小。 y 只是一个指针(不是数组),所以编译器就知道它了。另请注意:sizeof 是在编译时而非运行时评估的。
  • @user0042,即使std::array 也不存储大小。至少我希望实现不会那样做。
  • 在固定大小数组的情况下,比如问题中的x[10],编译器将大小“存储”在编译后的代码中,比如sizeof(x)最终作为一个常量编译代码中的 40,因为正如 Richard Critten 所指出的,sizeof() 是在编译时评估的。
  • 它是类型的一部分。 int[10]int[8] 是不同的类型。编译器知道这个信息,所以它可以得到它的大小。

标签: c++ arrays memory-management


【解决方案1】:

数组的大小不需要存储,编译器自己知道它有多大,因为它是类型的一部分。

当您像在示例中对 y 所做的那样动态分配数组时,数组的大小确实需要存储在某个地方,以便 delete[] 可以做正确的事情。但这是程序无法访问的实现细节。

【讨论】:

    【解决方案2】:

    你有两种不同的类型:

    int x[10];
    

    这声明了int[10] 的类型。如您所见,数组的大小是类型的一部分。

    int * y;
    

    这是一个指向 int 的指针。它的大小与系统上指针的大小相等。您的系统似乎有 64 位指针(现在很常见)。


    这是你可以在 C++17 中做的一个小技巧:

    template<class T>
    std::enable_if_t<std::is_pointer_v<T>> foo(T ptr)
    {
        std::cout << "Called foo for a pointer type" << std::endl;
    }
    
    template<class T, int N>
    void foo(T (&arr)[N])
    {
        std::cout << "Called foo for an array type of size " << N << std::endl;
    }
    

    我们定义了两个名为foo 的函数。第一个使用类型特征仅启用指针类型,第二个用于数组类型(通过引用)。

    我们可以从 main 调用它们:

    int x[10];
    int * y = nullptr;
    foo(x);
    foo(y);
    

    并获得如下所示的输出:

    为大小为 10 的数组类型调用 f​​oo
    为指针类型调用 f​​oo

    Runnable code


    编辑:Mark Ransom 很好地说明了为y 分配的数组的大小,我也将添加一小部分。虽然它确实是一个实现细节,但常见的是内存分配器的实现(如mallocnew)在底层会将此值写入它分配的内存块的开头。 这样,当您调用delete 时,您不必知道要删除多少字节;释放器(freedelete)可以检查内存块的开始位置有多大。所以分配,比如说 1 个字节,实际上可能分配超过 1 个字节。 (同样,这只是一种方法)

    【讨论】:

    • 我喜欢这个答案,因为它提出了一些我以前不知道存在的东西。
    【解决方案3】:

    数组的大小在编译后的 C++ 代码(汇编代码)中很明显。这相当于sizeof() 在编译时的求值方式。

    结果,它不存储它,编译器知道数组的大小。

    当您动态分配内存时,编译器再次知道数组的大小并记住它(它由实现定义的位置和方式)。这样一来,当你调用delete[]时,不需要指定数组的大小,编译器就知道了。

    【讨论】:

    • 不是说这是一个糟糕的答案,但它怎么不完全等同于@MarkRansom 的答案?
    • @Sheljohn 确实如此。在马克发布他的答案之前,我开始写我的答案(因为我正在仔细检查)......
    猜你喜欢
    • 2012-06-12
    • 2016-10-29
    • 2014-11-15
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多