请考虑以下代码,它们将准确success
引用三遍:
int arr [3];
for(int& value : arr )
std::cout << "success" << std::endl;
如果我尝试在堆上分配数组,则会出现问题。此代码无法编译:
int* ptr = new int[3];
for(int& value : *ptr )
std::cout << "success" << std::endl;
由于指针已被取消引用,因此类型应相同。所以我有一些问题:
答案 0 :(得分:4)
如果可见声明包含元素数,即原始情况下的int arr[3]
和第二情况下的int* prt
,则原始数组仅支持基于范围的语法。在第一种情况下,给出了此信息(但是,如果可能,您仍应首选std::array
),但是在第二种情况下,则不会在堆上分配内存,并且有关大小的信息已消失。如果您仅使用std::array
而不是原始数组,则可以避免这种情况。
由于指针已被取消引用,因此类型应相同。
仔细研究一下,原因是,在第一种情况下,您有一个数组,在第二种情况下,您有一个指针,即使相同的类型也不
这种对指针和数组相等性的误解一直在C ++教程中传播,但这是错误的。这可能是由于以下事实:将数组传递给带有该类型指针的函数时,数组 decays 指向一个指针,即 array-decay 。
我可以做一点改动吗
可以。使用std::array
或st::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;
}
为简便起见,我没有包括您应该经常删除的指针。
但是,如果您在堆上分配内存,则几乎总是最好使用std::vector
,因为自动分配会自动处理。该程序将显示为:
#include <iostream>
#include <vecor>
int main()
{
std::vector<int> vec(3);
for(int& value : vec)
std::cout << "success" << std::endl;
}
答案 1 :(得分:4)
由于指针已被取消引用,因此类型应相同。
仔细查看指针的类型:int* ptr
。它是指向int
的指针,将其与arr
的类型int[3]
进行比较。这些类型是不同的。因此,您认为类型应该相同是错误的。 int[3]
是范围,而int
不是范围。
array-new-expression返回一个指向数组第一个元素的指针。这就是ptr
所指向的。第一个元素的内存地址与整个数组相同,但是变量的类型决定了如何使用它。
我可以做一点零钱吗?
由于指向第一个元素的指针的值与指向整个数组的指针的值相同,因此可以使用强制转换将指针重新解释为另一种类型:
auto arr_ptr = std::launder(reinterpret_cast<int (*)[3]>(ptr));
for(int& value : *arr_ptr)
也就是说,通常使用动态数组,因为它们允许在运行时确定大小。该强制类型转换的大小必须在编译时就知道。
此外,您的示例代码泄漏了数组。尽管此代码中的泄漏很容易修复,但是手动进行内存管理通常很困难,而且没有必要。当然,当您需要动态数组时,最好使用std::vector
:
std::vector<int> v(3);
for(int& value : v)