【问题标题】:How does std::end know the end of an array?std::end 如何知道数组的结尾?
【发布时间】:2016-02-03 10:34:10
【问题描述】:

std::beginstd::end 知道 containerarray 的开头和结尾。

例如,很容易知道vectorendbegin,因为它是一个提供此信息的类。但是,它如何知道array 的结尾,如下所示?

int simple_array[5]{1, 2, 3, 4, 5};
auto beg=std::begin(simple_array);
auto en=std::end(simple_array);

std::begin 并不难知道数组从哪里开始。但是它怎么知道它在哪里结束呢?常量整数5 会存储在某处吗?

如果我能得到一些低级信息的答案,我将不胜感激。

【问题讨论】:

    标签: c++ arrays c++11


    【解决方案1】:

    但是,它怎么知道数组的结尾

    它使用模板非类型参数来推断数组的大小,然后可以使用它来生成结束指针。 std::end 的 cppreference 部分的 C++11 签名如下:

    template< class T, std::size_t N >
    T* end( T (&array)[N] );
    

    正如 hvd 所指出的,由于它是通过引用传递的,因此可以防止衰减到指针。

    实现类似于:

    template< class T, std::size_t N >
    T* end( T (&array)[N] )
    {
        return array + N ;
    }
    

    常量整数 5 会存储在什么地方吗?

    5N 是数组类型的一部分,因此 N 在编译时可用。例如,将sizeof 应用于数组将得到数组中的总字节数。

    很多时候我们看到一个数组通过值传递给一个函数。在这种情况下,数组decays to a pointer 以类型存储在数组中。所以现在尺寸信息丢失了。通过引用传递可以让我们避免这种信息丢失并从类型中提取大小N

    【讨论】:

    • 谢谢,这是否意味着 N 存储在某个地方?如果是,在哪里?
    • N 由函数存储。一旦函数执行完毕,它就会丢失。如果你想达到同样的效果并返回数组的大小,你可以使用这个答案中提供的代码,只返回 N。
    • @HumamHelfawi 你知道我之前错过了你评论的重点,并在我上下班时意识到你的意思。我更新了我的答案以正确涵盖您的评论。
    • 是的,我现在更清楚了。非常感谢@ShafikYaghmour
    • @HumamHelfawi:实际上,数组大小确实存储在代码中的某处=>。对于每个不同的元组(T, N),会生成一个不同的std::end&lt;T, N&gt; 实例并将其作为代码存储在发出的库/二进制文件中。优化编译器可能意识到它是无用的,并对其进行优化(只留下结果array + N),但即便如此,这个 N 也会因此出现在生成的代码中(作为常量)。跨度>
    【解决方案2】:

    是常量整数 5 会存储在什么地方吗?

    是的,它是数组类型的一部分。但是不,它没有明确存储在任何地方。当你有

    int i[5] = { };
    

    i 的类型是int[5]。 Shafik 的回答谈到了如何使用这个长度来实现end

    如果您使用 C++11,使用 constexpr 将是最简单的方法

    template <typename T, size_t N>
    inline constexpr size_t
    arrLen(const T (&arr) [N]) {
        return N;
    }
    

    如果您有一个 C++11 之前的编译器,其中 constexpr 不可用,则上述函数可能不会在编译时进行评估。所以在这种情况下,你可以这样使用:

    template <typename T, size_t N>
    char (&arrLenFn(const T (&arr) [N]))[N];
    
    #define arrLen(arr) sizeof(arrLenFn(arr))
    

    首先,我们声明一个函数,返回对 N 个数组的引用 chars 即 sizeof 这个函数现在将是数组的长度。然后我们有一个宏来包装它,以便它在调用者端是可读的。

    注意:两个基本类型相同但长度不同的数组仍然是两种完全不同的类型。 int[3]int[2] 不同。但是,Array decay 在这两种情况下都会为您提供int*。如果您想了解更多信息,请阅读How do I use arrays in C++?

    【讨论】:

    • 谢谢,看来我错过了很多东西.. 我真的应该问“什么是数组”.. 你的意思是数组是某种小类,有一个开始的指针和一个元素数量?你能指出我可以详细阅读它吗?
    • 两个基本类型相同但长度不同的数组仍然是两个完全不同的类型。 int[3]int[2] 不同。然而,数组衰减在这两种情况下都会给你一个int*。如果想了解更多关于数组的信息,请阅读How do I use arrays in C++?
    • 是的,这正是我从您的回答中得出的结论。再次感谢
    • @HumamHelfawi int[5] 的数组在内存中只有 5 个 ints 彼此相邻。大小不会在运行时存储在任何地方。该大小在编译时可用,因为它是数组类型的一部分。
    【解决方案3】:

    因为您将数组传递给std::end,而数组的类型为T [N]std::end 可以通过查看类型中的 N 来判断数组何时结束。

    【讨论】:

      猜你喜欢
      • 2012-04-30
      • 2014-09-18
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-24
      • 1970-01-01
      相关资源
      最近更新 更多