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

Hum*_*awi 29 c++ arrays c++11

std::beginstd::end知道一个container或一个的开始和结束array.

它很容易知道endbeginvector为例子,因为它是一个类,给出了这样的信息.但是,它如何知道如下结束array呢?

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

std::begin并不难知道数组的起始位置.但它如何知道它的结束?将常数整数5存储在某处吗?

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

leg*_*s2k 26

是常数整数5会存储在哪里?

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

int i[5] = { };
Run Code Online (Sandbox Code Playgroud)

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

如果您使用的constexpr是C++ 11,那么使用它将是一种简单的方法

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

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

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

#define arrLen(arr) sizeof(arrLenFn(arr))
Run Code Online (Sandbox Code Playgroud)

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

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

  • 两个相同基本类型但具有不同长度的阵列仍然是两种完全不同的类型.`int [3]`与`int [2]`不同.然而,数组衰减会在两种情况下都得到一个`int*`.如果想了解有关数组的更多信息,请阅读[如何在C++中使用数组?](http://stackoverflow.com/q/4810664/183120). (2认同)
  • @HumamHelfawi一个`int [5]`的数组在内存中只是5` int的旁边.大小不会存储在运行时的任何位置.大小在编译时可用,因为它是数组类型的一部分. (2认同)

Sha*_*our 25

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

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

template< class T, std::size_t N >
T* end( T (&array)[N] );
Run Code Online (Sandbox Code Playgroud)

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

实施类似于:

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

是否将常数整数5存储在哪里?

5或者N是数组类型的一部分,因此N在编译时可用.例如,将sizeof应用于数组将为我们提供数组中的总字节数.

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

  • @HumamHelfawi:实际上,数组大小确实存储在代码中的某处=>.对于每个不同的元组`(T,N)`,生成一个不同的`std :: end <T,N>`实例,并将其作为代码存储在发出的库/二进制文件中.优化编译器*可以*意识到它是无用的,并将其优化出来(只留下结果`array + N`),但即使这样,这个N也会出现在生成的代码中(作为常量). (2认同)

Sim*_*ple 8

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