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

时间:2015-11-03 10:07:53

标签: c++ arrays c++11

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

例如,很容易知道end的{​​{1}}和begin,因为它是一个提供此信息的类。但是,它如何知道vector的结尾如下?

array

int simple_array[5]{1, 2, 3, 4, 5}; auto beg=std::begin(simple_array); auto en=std::end(simple_array); 并不难知道数组的起始位置。但它如何知道它的结束?将常数整数std::begin存储在某处吗?

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

3 个答案:

答案 0 :(得分:25)

  

但是,它如何知道数组的结尾

它使用模板非类型参数来推断数组的大小,然后可以使用它来生成结束指针。来自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

答案 1 :(得分:23)

  

是常量整数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;
}

如果您使用constexpr不可用的C ++ 11之前的编译器,则可能无法在编译时评估上述函数。所以在这种情况下,您可以使用:

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

#define arrLen(arr) sizeof(arrLenFn(arr))

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

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

答案 2 :(得分:8)

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