C++中的'new'运算符和typedef数组

3

可能是重复的问题:
在C++中是否有可能动态创建一个常量大小的数组?

这其实是一个理论性的问题——我想知道为什么在C++中,operator new[]返回指向数组第一个元素的指针而不是实际的数组(或指向它的指针)。这个问题出现在我尝试做以下的事情时:

typedef int int4[4];
int4* ni4 = new int4;

虽然我知�为什么这�起作用(尽管一开始并�太清楚😉),但是真的很让我困扰,�则上�以使用A* ptr= new A;的代�无法编译。 我是唯一一个觉得这很奇怪的人�?


1
这是一个笔误还是你真的意思是 typedef int[4] int4; ? - Eric Fortin
1
@Eric:typedef 语法是正确的。但是下一行有一个打字错误,应该是 int4* ni4 = new int4; - Ben Voigt
使用 int[4] int4 时出现错误:在“[”标记之前预期未限定的 ID;第二个拼写错误已更正。 - j_kubik
哦,我不知道我们可以这样使用typedef,虽然我可能永远不会用到它,但了解这一点还是很好的。 - Eric Fortin
4个回答

2
我觉得这里很奇怪的是使用了operator new[]。如果聚合体是一个结构体,那么试图分配单个实例将是合法的。
但是,标准在 [expr.new]节中指出了这种行为。
然而,有一个非常简单的解决方法:
typedef int int4[4];
int4* ni4 = new int4[1];

...

delete [] ni4;

这真的很奇怪,这是标准行为。也许数组的typedef没有被视为聚合体?无论如何,感谢您提供的解决方法提示 - 它似乎比我一直在使用的int4* ni4 =(int4*) new int4;更好。但我的问题仍然存在 - 为什么标准会这样制定?我一直认为标准旨在实现完全的类型正确性 - 这似乎更像是违规... - j_kubik
为什么会奇怪呢?该代码尝试分配一个数组,因此使用了 operator new[]。这是标准规定的语义。那个人展示的代码等同于 new int[4],它使用完全相同的对象类型进行分配。 - Johannes Schaub - litb
@Johannes:在 new int[4] 中,数组说明符 [4] 实际上是 new-expression 语法的一部分,而不是类型的一部分。我通常期望具有可选的 noptr-new-declaratornew-expression 调用 operator new[](),而没有则调用 operator new()。目前特殊处理数组类型与其他聚合类型的行为使得编写模板代码变得困难。 - Ben Voigt
int[4]是一个new-type-id,它指定了一种类型。如果您将其用作new int[4],则告诉系统应创建一个类型为int[4]的对象。当然,[4]由某些语法产生式解析。所有规则都完全以“如果创建数组对象,则调用'operator new[]',否则使用'operator new'”为基础进行指定。我也认为期望您所说的并不完全脱离实际。当T是类型U[N]时,new T确实“看起来不同于”new U[N]。但从语言角度来看,它们是相同的。 - Johannes Schaub - litb

0

我不太确定我是否理解了你的问题。在C++中,就像在C中一样,指向数组第一个元素的指针和数组本身之间没有区别。

编辑:正如有人指出的那样,这并不完全正确 - 请原谅我的错误,最近我花了太多时间学习Java和C# ;-)


3
它们肯定有所不同 - 它们是不同类型的。 sizeof 将给出不同的结果,你可以编写函数以引用数组(特定大小的数组),但无法使用指针。 - Mike Seymour
1
这是错误的,存在很大的差异。数组不是指针,但在某些情况下可以被视为指针。一些区别包括:1.不同的sizeof 2.不同的初始化。 - Mihran Hovsepyan

0

以下内容可能可以被争论:

new (int[N]); // type int(*)[N]
new int[N]; // type int*
new T; /* T* */

只有在中间情况下,N 可以是运行时值。然而,规范并没有建立这样的类型差异。数组在几乎所有情况下都需要特殊处理(例如,你不能仅仅复制它们)。因此,你应该准备好特别处理它们。例如,在你的情况下,你还必须使用 delete[] 而不是 delete

只是为了明确,如果上述内容是真实的,那么你将需要笨拙的语法。

int (*p)[N] = new (int[N]);
(*p)[N-1] = 0;
p[0][N-1] = 0; /* or, equivalently */
p[N-1] = 0; /* but not this, error! */

你首先需要取消引用数组指针。


或者只是 int *p = new int[N]; - 如果上面的说法是正确的;) 但这取决于你需要什么 - 例如,将 (int[N]) 视为聚合体(与 struct { int f[N]; } 一起使用时,它会按照我想要的方式工作)。 - j_kubik
@j_kubik 我不明白你所说的“将(int[N])视为聚合”的意思。int[N]本身就是一个聚合体。数组是聚合体。 - Johannes Schaub - litb
这就是我的意思 - 数组是聚合体,但它们的语义与结构不同 - 如果您创建一个新的结构,则返回的指针指向整个结构,而不是其中的一部分。在数组的情况下,我希望返回数组指针。 - j_kubik

0

这是从C语言遗留下来的,而实际上C语言又是从B语言遗留下来的。在C++中处理本地数组的整个过程非常糟糕,但他们无法改变它。这在C++中存在许多问题。


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