使用多维数组在范围循环中进行 C++ 变量初始化

c++ variable initialization in ranged loops with mutidimentional arrays

我是第一次学习c++(我是从python转过来的)

当我尝试使用多维数组处理和编译范围循环时,我看到了一些奇怪的行为。考虑以下情况:

#include <iostream>
#include <typeinfo>

int array[2][3]
for (dataType row : array) { std::cout << typeid(row).name(); }

如果dataType是const int* row,row变成一个指针(其元素)不能被修改。这是预期的。

for (const int* row : array) { std::cout << typeid(row).name(); }

输出:int const * __ptr64

如果dataType是const auto row,row变成一个可以被修改的指针。无论您是否尝试修改代码中的行,编译器都会忽略您将行设为常量的请求。

for (const auto row : array) { std::cout << typeid(row).name(); }

输出:整数 * __ptr64

在上面的例子中,我可以修改行的内容,没有任何错误。

如果你在auto后面加上星号,你现在会得到一个常量变量。您需要同时输入 const,然后加上星号使其保持不变。

for (const auto* row : array) { std::cout << typeid(row).name(); }

输出:int const * __ptr64

现在,如果我们用 & 运算符代替星号,行将变成大小为 3 的数组。在这里,& 没有修改地址或任何东西,我找不到强制编译器复制的方法内部数组并将其放在新地址的行内。这只会让使用嵌套的范围循环变得更容易。

for (auto& row : array) { std::cout << typeid(row).name(); }

输出:整数[3]

但是现在,我无法手动告诉编译器创建一个数组。输入类似 int row[3] 的内容甚至不会被编译。获取数组的唯一方法是使用 auto&

for (int row[3] : array) { std::cout << typeid(row).name(); }

CompilerError E0144:“int*”类型的值不能用于初始化“int[3]”类型的实体

for (int& row[3] : array) { cout << typeid(n).name(); }

CompilerError E0144:“int*”类型的值不能用于初始化“int[3]”类型的实体

CompilerError E0251: 不允许引用数组

我喜欢在我的代码中使用嵌套的范围循环,这是我在使用 python 时养成的习惯。它使代码更易于编写和阅读,并且更不容易出错。为了可读性和调试,我想要一种方法来强制我的编译器将行初始化为数组而不是使用 auto& 并让编译器决定它想要数组的数据类型。

此外,我想要一种在另一个地址获取行的深层副本的方法,这样我就可以在不更改原始数组的情况下修改循环内的内容。对于一维循环,省略 & 运算符将在不同的地址复制数据,但对于多维数组,它始终是相同的地址。

如果您知道使用 const auto 而不是 const auto* 进行初始化时发生了什么,那就太好了。添加星号对编译器如此重要有什么作用?

C 数组不可复制,引用类型具有 strange/ugly 语法。

我建议使用 std::array,这是一个很好的替代品。

std::array<std::array<int, 3>, 2> array;
for (/*const*/ std::array<int, 3> /*&*/ row : array) {
    for (int /*&*/ e : row) {
        // ...
    }
}
for (/*const*/ auto /*&*/ row : array) {
    for (auto /*&*/ e : row) {
        // ...
    }
}

C 数组只允许通过引用传递(否则衰减为指针)

int array[2][3];
for (/*const*/ int (&row)[3] : array) {
    for (int /*&*/ e : row) {
        // ...
    }
}
for (/*const*/ auto & row : array) {
    for (auto /*&*/ e : row) {
        // ...
    }
}

归功于 M.M:

for (const auto row : array) { std::cout << typeid(row).name(); }

这里的auto变成了一个指针,然后const应用到它上面。它是一个指针,指针存储的地址不能改变,但它指向的值可以改变。

写法一样:

int* const row

相反,const auto* 只是如预期的那样变成 const int*

编译器从左到右读取,所以这里 const int* 等同于 (const int)* 创建一个指向数据类型 const int 的指针,而 int* const 创建一个指针然后应用 const指向那个指针。

归功于 Igor Tandetnik:

要引用子数组,您需要编写以下内容:

for (int (&row)[3] : array) {}

对于多维数组,一般语法为:

dataType array[a][b][c][d](...) ;
 
for (dataType (&row)[b][c][d](...) : array) {}

要复制数组,您可以使用指针并使用 for 循环手动完成。根据您正在做的事情,您应该选择是否要在堆上分配它。或者,有一些 C++ 库可以为您提供 copy() 函数。