C ++中的动态零长度数组

时间:2018-04-30 18:08:09

标签: c++ arrays c++11 new-operator dynamic-memory-allocation

#include <stdlib.h>

void *operator new[](size_t size, int n){
    if( size != 0 && n != 0 )
        return calloc(n, size);
    return calloc(1, 1);
}

int main(){

    int * p1;
    const int i = 0;

//  p1 = new (20)  int[i] ; // Case 1 (OK)
    p1 = new (20) (int[i]); // Case 2 (Warning)

    if( p1 == 0 )
        return 1;
    return 0;
}

此代码(https://godbolt.org/g/hjo7Xn)与Clang 6.0.0成功编译,但是,GCC 7.3发出警告说在C ++中禁止使用零长度数组。如果删除了括号(案例1),警告就会消失。

与静态分配的零长度数组(C ++ 03:8.3.4 / 1)不同,允许动态分配的零长度数组(C ++ 03:5.3.4 / 6)。然而,在C ++标准中,只有在遵循 new-expression 的两个可能语法路径之一时,才明确允许后者,即具有 new-type-id的那个 em>且没有括号(案例1)。

C ++标准是否允许在第二个语法路径之后使用带有零长度数组的 new-expression ,即使用 type-id 和括号(案例2)?

唯一相关的引用是C ++ 03:5.3.4 / 5:

  

当分配的对象是数组时(即使用 direct-new-declarator 语法或 new-type-id 类型 - id 表示数组类型), new-expression 生成一个指向数组初始元素(如果有)的指针。

措辞(if any)将允许没有元素的数组,但是,它似乎不清楚它是指两种情况还是只引用 new-type-id 和没有括号(案例1)。

提前致谢。

注意:

  1. ISO / IEC 14882:2003,第8.3.4节,第1段:
      

    如果存在常量表达式(5.19),则它应为整数常量表达式,其值应大于零。

  2. ISO / IEC 14882:2003,第5.3.4节,第6段:
      

    direct-new-declarator 中的表达式应具有带有非负值的整数或枚举类型(3.9.1)。

  3. ISO / IEC 14882:2003,第5.3.4节,第7段:
      

    direct-new-declarator 中的表达式的值为零时,调用分配函数来分配没有元素的数组。

  4. ISO / IEC 14882:2003,第5.3.4节,第1段:
      

    新表达

         

    :: opt 新展示位置 opt new-type-id new-初始化 opt

         

    :: opt 新展示位置 opt type-id new-初始化 opt

  5. 虽然以上引用来自C ++ 03标准,但据我所知,这个问题在较新版本的C ++标准(C ++ 11,C ++ 14和C ++ 17)中仍然不清楚。
  6. 有趣的Herb Sutter post关于零长度数组。
  7. 示例中的代码是来自SolidSands' SuperTest套件的稍微修改过的测试。

2 个答案:

答案 0 :(得分:2)

使用括号,您可以使用常规 type-id ,而不是支持动态数组大小的名为 new-type-id 的特殊语法。

从C ++ 17开始,标准对 type-id 的使用没有特别的规定,所以问题归结为你是否可以写

std::size_t

您不能,因为 type-id 的类型是根据虚构的“声明该类型的变量或函数的声明来省略实体的名称”(C ++17§11.1/ 1),对于数组变量的声明,规则是“如果存在常量表达式(8.20),它应该是size_t类型的转换常量表达式,其值应为大于零“(C ++17§11.3.4/ 1)。

现在有一些相关的解释。例如。如果没有这样合理的解释,最后的引用就不能合理地说数组大小必须是非负的并且可以表示为int x[42]; 。相反,如果没有合理的解释,它会直接说出一个声明,例如

int x[std::size_t(42)];

无效(当然不是),并且必须表示为

{{1}}

确定什么是合理的解释或过去很容易。人们可以问,它有意义吗?因此对于上述情况,答案是否定的,人们可能会放弃这种可能性。

然而,在某种程度上使用C ++ 14并且越来越多地使用C ++ 17,我发现早期的可靠技术失败了。由于手头的问题是关于C ++ 03的功能,我认为你可以相信这个答案。但如果它是关于C ++ 14或更高版本的问题,那么请记住,任何明显清晰的答案可能涉及一些主观解释,可能无法通过询问它是否有意义来解决。

答案 1 :(得分:0)

不,零大小写不能使用带括号的 type-id 。仅对 noptr-new-declarator [expr.new]/7)中的表达式给出了大小为0的数组的行为(在当前草案中)。具有括号类型的new尝试创建该类型的对象,并且没有大小为0的数组([dcl.array]/1),甚至不是类型-id [dcl.name]/1)。

零大小的数组当然是常见的扩展,因此实际结果可能会有所不同。