在数组上使用迭代器

Using iterators on arrays

本文关键字:迭代器 数组      更新时间:2023-10-16

c++ Primer中指出

在c++中,指针和数组是紧密联系在一起的。特别是,我们将看到,当使用数组时,编译器通常会转换.

我想使用迭代器打印数组。下面的程序工作正常,但当我尝试打印arr2arr3时,如果我没有搞错,这是int *类型,我得到一个错误(判断&操作符的含义如下)。

error: no matching function for call to ‘begin(int*&)’

int main(int argc, char** argv) {
    int arr[] = {0,1,2,3,4,5,6,7,8,9};
    auto arr2 = arr;
    auto arr3(arr);   // I think arr2 and arr3 are of same type
    for(auto it = std::begin(arr) ; it != std::end(arr) ; ++it)
        std::cout << *it << " ";
    std::cout << std::endl;
    return 0;
}

考虑到语句,如果一个数组被编译器转换成指针,这个程序怎么能用std::begin()std::end()打印arr的内容,而不能用arr2arr3,如果它们都是指向整数的指针?


编辑

如果我没说清楚,我很抱歉。我希望通过这次编辑能澄清这个问题。

现在我知道begin()end()不能使用指针(多亏了答案),我想知道引用的文本是否不正确,因为它指定有一个数组->指针转换。如果文本说的是真的,那么arr的类型应该是一个指针。在这一点上引用的文本有问题吗?

此外,是否有任何方法,我可以使用begin()end()指针(不是STL容器)指定大小,可能使用以下构造函数?

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

数组很容易转换为指针,但并非总是如此。例如,如果您获取数组的地址或获取引用,则原始数组类型不会丢失:

int a[10];
int (&ar)[10] = a; // fine
int (*ap)[10] = &a; // also fine

然而,当你以一种大多数其他类型都会被复制的方式使用数组时,数组将被转换为指针,而指针将被复制。

在你的例子中,你可以使用arr2,如果你让它是一个引用:

 auto &arr2 = arr;

现在arr2的类型是int (&)[10]而不是int *

因为std::begin是为数组而不是指针定义的。数组类型与指针类型不同。

这里的问题显然是auto arr2 = arr将数组类型降级为指针类型。

请注意,问题实际上是在std::end而不是在std::begin。毕竟,std::end如何能够给指针到最后一个+1元素,当它所有的是指向第一个元素的指针?它不能,因此std::end不能为指针类型定义,因此std::begin对指针类型没有任何意义。

确切地说,arr的类型是int[10], arr2arr3的类型是int*。前者可以转化为后者,而后者不能。

这里,auto将把arr(数组类型)衰变为一个指针。 std::begin std::end 只能用于容器或数组,而不能用于指针。

源自c++ 11标准

§7.1.6.4汽车说明符 [dcl.spec.auto]

自动类型说明符表示要声明的变量的类型必须从其初始化式推导出来或者函数声明符应该包含尾随返回类型。

你的代码不能在这里工作,因为auto不能推断数组类型。就像:

char a[5];
auto b[5] = a;  // error, a evaluates to a pointer, which does
                // not match the array type
要使它工作,只需使用c++容器,如std::vector:
vector<int> arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

std::beginstd::end使用的参数是C风格的数组。

std::end的一个可能实现是:

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

这样当你调用std::end(arr)时,arr不会在指针中转换(并且关于数组大小的信息不会丢失…该函数只接受包含sizeOfArray元素作为参数的数组)。

template<class T>
T *end(T array[])
{
  // ?
}

将不起作用,因为T array[]的行为像一个平面指针(T *array),而不是一个真正的数组,当用作函数参数时。

auto将数组arr衰变成一个指针,技巧将不再起作用。