0

我是第一次学习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(); }

输出:int * __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(); }

输出:int [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* 进行初始化时,最好知道发生了什么。添加星号对编译器有何重要意义?

4

2 回答 2

1

C 数组是不可复制的,并且引用类型的语法很奇怪/丑陋。

我建议使用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-array 只允许通过引用传递(否则衰减到指针)

int array[2][3];
for (/*const*/ int (&row)[3] : array) {
    for (int /*&*/ e : row) {
        // ...
    }
}
for (/*const*/ auto & row : array) {
    for (auto /*&*/ e : row) {
        // ...
    }
}
于 2021-05-10T08:56:33.687 回答
0

归功于 MM:

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

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

和写法一样:

int* const row

相反,const auto*只是变得const int*如预期。

编译器从左到右读取,因此这里const int*等效于(const int)*创建指向数据类型的指针,const intint* const创建指针然后将 const 应用于该指针。

归功于伊戈尔·坦德尼克:

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

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

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

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

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

于 2021-05-18T23:28:40.090 回答