为什么不能在新的初始值设定项中省略数组大小?

时间:2014-12-18 22:29:05

标签: c++ c++11 language-lawyer

这是允许的:

int a[]{1, 2, 3};

但不是这样:

auto a = new int[]{1, 2, 3};

您必须指定边界。为什么呢?

编辑:正确的语法(不编译)是:

auto a = new (int[]){1, 2, 3};

这给出了真正的错误消息,即:

error: invalid use of array with unspecified bounds

3 个答案:

答案 0 :(得分:9)

MSalters' answer解决了为什么在最新版本的标准中没有改变这一点的原因。在这里,我将回答同伴问题,“C ++ 11标准在哪里被禁止?”

关于new (int[]){1, 2, 3}

首先,我们需要注意int[]是一种不完整的类型。

  

...未知大小的数组...是一个未完全定义的对象类型。 - [basic.types]§3.9¶5

最后,我们注意到new运算符不允许指定的类型不完整:

  

此类型应为完整的对象类型... - [expr.new]§5.3.4¶1

当使用 braced-init-list 语法时,标准中没有任何内容可以例外。

关于new int[]{1, 2, 3}

在这种情况下,

int[]使用 new-type-id 生产进行解析,该生产使用 noptr-new-declarator 生产来解析方括号:

  

noptr新声明符:
  [表达式] attribute-specifier-seq opt
   noptr-new-declarator [ constant-expression ] attribute-specifier-seq opt

请注意,表达式未标记为可选,因此此语法无法解析。

答案 1 :(得分:5)

正如Jonathan Wakely在评论中已经指出的那样,这实际上是一个封闭的问题。决议“应该在Evolution工作组中处理”实质上意味着WG21认为这本身并不是一个坏主意,但与此同时他们并不认为它是当前标准中的缺陷。这是有道理的 - 没有任何提示应该起作用的暗示,这只是类比。

答案 2 :(得分:0)

我认为这是因为编译器以串行方式读取文件,它永远不会返回,(这就是为什么你必须使用前向声明,而不是等待函数稍后声明)。我不确定这是官方的原因,但它对我来说才有意义。

这是我的解释:

int Array[]={1,2,3};可以按照以下方式连续处理:

启动数组:将1放在第1位,将2放在第2位,将3放在第3位,结束数组,因此:数组大小为3个整数,因此按此大小移动堆栈帧。

但是以下行:int *p=new int[]{1,2,3};除了将元素放在内存中并检测大小外,还应该从内存分配开始。怎么能以连续的方式完成?

要允许这样的事情,你必须打破连续性原则,并从最后开始处理,然后返回调用适当的分配大小。

修改

回应第1条评论

我做了一些测试,在下面的代码中:

class A{
public:
    A(){
        err2 error;
        cout<<sizeof(A)<<endl;
    }
    err1 error;
};

编译器似乎将内联函数保留为在类之后进行编译。

证据是无论顺序如何,在功能错误之前检测到成员错误。 所以在示例类中,我在err1 error之前得到err2 error,即使按时间顺序相反。

因此,我认为类是特殊的,否则课堂本身的使用非常有限。

<强> EDIT2:

int Array[]={sizeof(Array)};给出错误,唯一的原因是在关闭数组后给出数组的大小。它与int Array[]={1,2};

中的问题更相似