std::end 如何知道数组的结尾

How does std::end know the end of an array?

本文关键字:结尾 数组 end std 何知道      更新时间:2023-10-16

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会存储在某个地方吗?

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

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

它使用模板非类型参数来推断数组的大小,然后可以使用该参数生成结束指针。std::end 的 cpp首选项部分中的 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 应用于数组将给我们数组中的字节总数。

很多时候,我们看到一个数组按值传递给函数。在这种情况下,数组将衰减到指向存储在数组中的类型的指针。所以现在大小信息丢失了。通过引用传递,我们可以避免这种信息丢失,并从类型中提取大小N

常量整数 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 char s 数组的引用,即 sizeof此函数现在将是数组的长度。然后我们有一个宏来包装它,以便在调用方端可读。

注意:两个基本类型相同但长度不同的数组仍然是两种完全不同的类型。 int[3]int[2]不同.但是,在这两种情况下,数组衰减都会使您int*。阅读如何在C++中使用数组?如果你想了解更多。

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