#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)。
提前致谢。
注意:
如果存在常量表达式(5.19),则它应为整数常量表达式,其值应大于零。
direct-new-declarator 中的表达式应具有带有非负值的整数或枚举类型(3.9.1)。
当 direct-new-declarator 中的表达式的值为零时,调用分配函数来分配没有元素的数组。
新表达:
::
opt
新 新展示位置opt
new-type-id new-初始化opt
::
opt
新 新展示位置opt
( type-id ) new-初始化opt
答案 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)。
零大小的数组当然是常见的扩展,因此实际结果可能会有所不同。