基于范围的堆分配数组的循环

Mik*_*Rev 5 c++ pointers c++11

考虑下面的代码,该代码将success准确显示三遍:

int arr [3];

for(int& value : arr )
    std::cout << "success" << std::endl;
Run Code Online (Sandbox Code Playgroud)

如果我尝试在堆上分配数组,则会出现问题。该代码无法编译:

int* ptr = new int[3];

for(int& value : *ptr )
    std::cout << "success" << std::endl;
Run Code Online (Sandbox Code Playgroud)

由于指针已取消引用,因此类型应相同。所以我有一些问题:

  • 当我从两个表达式中的硬件询问时,两者之间的根本区别是什么。我想了解为什么后者没有意义。
  • 我可以做一点零钱吗?

eer*_*ika 5

由于指针被取消引用,因此类型应该相同。

仔细看看指针的类型:int* ptr。它是一个指向intCompare的指针,它的类型arrint[3]。这些类型是不同的。因此,您认为类型应该相同的假设是错误的。int[3]是一个范围,而int不是。

array-new-expression 返回指向数组第一个元素的指针。这就是ptr指向。第一个元素的内存地址与整个数组相同,但变量的类型决定了它的使用方式。

我可以通过一个小的改变让它工作吗?

由于指向第一个元素的指针的值与指向整个数组的指针相同,您可以使用强制转换将指针重新解释为另一种类型:

auto arr_ptr = std::launder(reinterpret_cast<int (*)[3]>(ptr));
for(int& value : *arr_ptr)
Run Code Online (Sandbox Code Playgroud)

也就是说,通常使用动态数组,因为它们允许在运行时确定大小。在编译时必须知道该类型转换的大小。

此外,您的示例代码会泄漏数组。虽然此代码中的泄漏很容易修复,但手动内存管理通常很困难,而且没有必要。std::vector当您需要动态数组时,您肯定最好使用:

std::vector<int> v(3);
for(int& value : v)
Run Code Online (Sandbox Code Playgroud)

  • 我总是不确定重新解释演员。 (2认同)

小智 4

如果可见声明包含元素数量,即int arr[3]在第一种情况和int* prt第二种情况下,原始数组仅支持基于范围的 for 语法。在第一种情况下,这是给定的(但std::array如果可能的话,您仍然应该更喜欢),但在第二种情况下,您在堆上分配内存并且有关大小的信息消失了。如果您只是使用std::array而不是原始数组,则可以规避此问题。

由于指针被取消引用,因此类型应该相同。

仔细观察一下,其原因是,在第一种情况下您有一个数组,在第二种情况下您有一个指针,它们甚至不是同一类型。

这种对指针和数组相等性的误解不断在 C++ 教程中传播,但这是错误的。这可能是因为,当将数组传递给采用该类型指针的函数时,数组会衰减为指针,称为数组衰减

我可以通过一个小改动让它工作吗

是的你可以。使用std::arrayorst::vector会使它看起来像std::array

#include <iostream>
#include <array>

int main()
{
    std::array<int, 3>* ptr = new std::array<int, 3>;

    for(int& value : *ptr )
        std::cout << "success" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,我没有包含您应该始终执行的指针删除操作。

但是,如果您在堆上分配内存,则最好使用它,std::vector因为会自动处理释放。该程序将读取:

#include <iostream>
#include <vecor>

int main()
{
    std::vector<int> vec(3);

    for(int& value : vec)
        std::cout << "success" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)