为什么这是一个错误:
typedef int H[4];
H * h = new H; // error: cannot convert 'int*' to 'int (*)[4]' in initialization
?
此外,为什么这不是错误:
H * h = new H[1];
?
为什么编译器认为
new H
返回int *
,而new H[1]
返回预期的H *
?换句话说:为什么
T * t = new T;
对于常规类型T是正确的,但是当T
是数组类型时为什么不正确? 通过
new
分配诸如此类的简单数组类型的规范方法是什么?请注意,这是一个简化的示例,因此
new int[4]
不是可接受的解决方法-我需要使用前面typedef
中的实际类型。还要注意,我知道使用
std::vector
,std::array
等通常比C样式数组更可取,但是我有一个“真实世界”用例,需要使用上述类型。 最佳答案
new T
的返回类型和值的C++规则是:
T
不是数组类型,则返回类型为T *
,并且返回值是指向T
类型的动态分配对象的指针。 T
是U
类型的数组,则返回类型是U *
,返回值是指向U
类型动态分配的数组的第一个元素(其类型是T
)的指针。 因此,由于您的
H
是int
的数组,因此new H
的返回类型是int *
,而不是H *
。根据相同的规则,
new H[1]
返回H *
,但是请注意,您已经在技术上分配了int
的二维数组,大小为1 x 4。在通用代码中解决此问题的最佳方法确实是使用
auto
:auto h = new H;
或者,如果您希望突出显示指针事实:
auto *h = new H;
至于规则中看似不一致的基本原理:在C++中,数组指针是非常“危险的”,因为它们的行为非常出乎意料(即,您必须非常小心以免产生不良影响)。让我们看一下这段代码:
typedef int H[4];
H *h = obtain_pointer_to_H_somehow();
h[2] = h[1] + 6;
乍一看(甚至可能第二眼),上面的代码似乎将6添加到数组中的第二个
int
并将其存储在第三个int
中。但这不是它的作用。就像
int *p
一样,p[1]
是int
(位于距sizeof(int)
偏移的p
字节地址处),因此,对于H *h
来说,h[1]
是H
,位于距4 * sizeof(int)
偏移地址h
字节处。因此,代码被解释为:接收h
中的地址,向其中添加4 * sizeof(int)
字节,然后添加6,然后将结果地址存储在8 * sizeof(int)
与h
偏移的位置。当然,这会失败,因为h[2]
衰减为右值。好的,您可以这样修复它:
*h[2] = *h[1] + 6;
现在更糟。
[]
的绑定(bind)比*
紧密,因此它将到达int
之后的第5个h
对象(请注意那里只有4个!),加6,然后将其写入int
之后的第9个h
中。写入随机存储器FTW。要实际执行代码可能打算执行的操作,必须将其拼写如下:
(*h)[2] = (*h)[1] + 6;
鉴于上述情况,并且由于通常对动态分配的数组执行的操作是访问其元素,因此
new T[]
返回T *
更为有意义。关于c++ - `new`指向数组的指针的首选方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37203859/