指向数组的`new`指针的首选方法

Pau*_*l R 16 c++

为什么这是一个错误:

typedef int H[4];

H * h = new H;        // error: cannot convert 'int*' to 'int (*)[4]' in initialization
Run Code Online (Sandbox Code Playgroud)

此外,为什么这不是一个错误:

H * h = new H[1];
Run Code Online (Sandbox Code Playgroud)

为什么编译器认为new H返回an int *,而new H[1]返回an H *按预期?

换句话说:为什么T * t = new T;普通类型T是正确的,但是当T数组类型不正确时?

分配简单数组类型的规范方法是new什么?

请注意,这是一个简化的示例,因此例如new int[4]不是可接受的解决方法 - 我需要使用前面的实际类型typedef.

另请注意,我知道,使用std::vector,std::array,等人一般都在C风格数组更好,但我有一个"真实世界"的使用情况下,我需要与类型的合作,如上述.

Rei*_*ica 15

返回类型和值的C++规则new T是:

  • 如果T不是数组类型,则返回类型为T *,并且返回的值是指向动态分配的类型对象的指针T.
  • 如果T是类型的数组U,则返回类型为U *,并且返回的值是指向U动态分配的类型数组的第一个元素(其类型为)的指针T.

因此,既然你H是一个数组int,返回类型new Hint *,不是H *.

按照相同的规则,new H[1]返回H *,但请注意,您已经技术分配了一个二维数组的ints,大小为1 x 4.

在通用代码中解决此问题的最佳方法确实是使用auto:

auto h = new H;
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望突出显示指针事实:

auto *h = new H;
Run Code Online (Sandbox Code Playgroud)

至于规则中看似不一致的基本原理:指向数组的指针在C++中非常"危险",因为它们表现得非常意外(即你必须非常小心它们才能产生不必要的效果).我们来看看这段代码:

typedef int H[4];
H *h = obtain_pointer_to_H_somehow();
h[2] = h[1] + 6;
Run Code Online (Sandbox Code Playgroud)

在第一次(甚至可能是第二次)一瞥时,上面的代码似乎int在数组中将第二个加到第二个并将其存储在第三个中int.但这不是它的作用.

就像是int *p,p[1]是一个int(在地址sizeof(int)字节偏移p),所以for 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;
Run Code Online (Sandbox Code Playgroud)

现在更糟糕了.[]结合更紧相比*,因此这将伸入5日int之后的对象h(注意,只是其中的4有!),加上6,并编写成9日int之后h.写入随机存储器FTW.

要实际执行代码可能的目的,它必须拼写如下:

(*h)[2] = (*h)[1] + 6;
Run Code Online (Sandbox Code Playgroud)

鉴于上述情况,并且由于您通常使用动态分配的数组来访问其元素,因此new T[]返回更有意义T *.

  • @MM:`T*p = new T;`对于某些类型(作为数组,引用)不起作用,这似乎很奇怪). (3认同)