在C++中是否可以动态创建一个固定大小的数组?

17
首先,我想向大家保证,我提出这个问题只是出于好奇心。我的意思是,不要告诉我如果我需要这个东西,那么我的设计就有问题,因为在实际代码中我并不需要它。希望我已经说服了你们 :) 现在来看看问题:
对于大多数类型T,我们可以写成:
T* p = new T;

如果T是一个数组类型,会怎样呢?

int (*p)[3] =  new ???; //pointer to array of 3 = new ???

我尝试了这个:
typedef int arr[3];
arr* p = new arr;

但这并不起作用。

有没有有效的语法可以实现这一点,还是在C ++中不可能?如果不可能,那么为什么?谢谢。

编辑:我猜我没有表述清楚。我希望能够在以下情况下使用它:

void f(int(&)[3]);
int (*p)[3] = new ???;
f(*p);

如果我理解正确,你想知道C++是否有一种方法可以在分配中不明确指定数组大小的情况下“推断”出数组的大小? - oakley.aaron
@oakley:不完全正确:我在问当T是一个数组类型(具有编译时已知的维度)时,是否可以使用T* p = new T;语法。 - Armen Tsirunyan
4个回答

11
new获取指向数组的指针,您需要动态分配一个二维数组:
int (*p)[3] = new int[1][3];

嗯... 不太符合我的期望,但我的例子肯定能工作... +1 - Armen Tsirunyan

10
你不能这样做的原因是new int[3]已经分配了你想要的准确对象,即int [3]类型的对象。只是新表达式返回的是指向其第一个元素的指针。根据5.3.4/1:

如果实体是非数组对象,则new-expression返回指向创建的对象的指针。如果它是数组,则new-expression返回指向数组的初始元素的指针。

返回指向第一个元素的指针允许3在运行时是未知的,所以我认为通过提前知道它,你已经遇到了你没有使用的灵活性。

我猜解决这个问题的方法是重新解释回你想要的指针类型(不一定可移植),或者分配一个包含int [3]的结构体(并使用指向其数据成员的指针)。

[编辑:嗯,是的,或者FredOverflow的想法,它既没有缺点,但需要使用delete[]而不是delete。]

我想道德是,如果你编写模板,用new天真地分配某些未知类型T,那么当有人将数组类型作为T传递时,模板将无法工作。你将把它分配给错误的指针类型,如果你修复了它(也许是用auto),你将错误地删除它。

编辑回答j_kubik的问题:

这里有一种区分数组和非数组类型的方法。如果你编写一个像这样的函数,返回一个持有指针并能够正确删除它的对象,那么你就有了任何类型T的通用new/delete。

#include <iostream>

template <typename T>
void make_thing_helper(T *) {
    std::cout << "plain version\n";
}

template <typename T, int N>
void make_thing_helper(T (*)[N]) {
    std::cout << "array version\n";
}

template <typename T>
void make_thing() {
    make_thing_helper((T*)0);
}

int main() {
    typedef int T1;
    typedef int T2[3];
    make_thing<T1>();
    make_thing<T2>();
}

1
new int[3]new int[1][3] 都需要通过 delete[] 释放。 - fredoverflow
1
@FredOverflow:确实,我是指“而不是”非数组类型发生的情况。如果我正在发明阿尔门想要的魔法不存在的语法,以分配一个数组类型的单个对象,就好像它是非数组类型,那么它将允许您通过从MagicNew返回的相同指针删除它。因此,它看起来像typedef int arr[3]; arr *p = MagicNew arr; delete p;。我知道他在问题中没有指定这一点,也许我假设其他人会以同样的方式发明它是错误的。 - Steve Jessop
总结一下,有没有办法使新的删除模板适用于数组类型,还是根本不可能? - j_kubik
@J_kubik:我认为你可以做到,但是你需要在某个地方区分T是否为数组类型。我会在我的答案中添加一种方法来解决这个问题。 - Steve Jessop

2
您可以始终使用boost::array,这将在C++0x中提供。 否则,任何解决方案都会变得尴尬:数组在C中已经损坏,在这方面,C++保持与C的兼容性。Fred Overflow提供了一种解决方案; 更简单(但语法上很嘈杂)的方法是将数组包装在结构体中: struct A { int arr[3]; }; 并分配和操作它。

那只是一个变通方法,而不是解决办法 :) @Fred的也是如此,但至少我的例子与他的变通方法相容。而对于你的来说,行不行? - Armen Tsirunyan
1
这个 wrapper 是一种解决方法,但 boost:array 是我在处理固定大小数组时更喜欢的解决方案。非常奇怪但也可能行得通:void f(array<3>& p); array<3>* p = new array<3>; f(*p); - stefaanv

-2

你只需要这样做

int *p = new unsigned int [3]

你可以使用*p作为指针或数组,例如*(p+1)或p[1]


2
抱歉,这完全不是我所询问的。 - Armen Tsirunyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接