c++ - C++ 中的动态零长度数组
问题描述
#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且不带括号的语法路径(案例 1)。
C++ 标准是否允许在第二个语法路径之后使用带有零长度数组的new-expression ,即使用type-id和括号(案例 2)?
唯一相关的引用是 C++03:5.3.4/5:
当分配的对象是一个数组(即使用直接新声明符语法或new-type-id或type-id表示数组类型)时,new-expression产生一个指向初始元素的指针(如果任何)的数组。
该措辞(if any)
将允许一个没有元素的数组,但是,似乎不清楚它是指这两种情况还是仅指具有new-type-id且不带括号的一种情况(情况 1)。
提前致谢。
笔记:
- ISO/IEC 14882:2003,第 8.3.4 节,第 1 段:
如果常量表达式(5.19) 存在,它应该是一个整数常量表达式并且它的值应该大于零。
- ISO/IEC 14882:2003,第 5.3.4 节,第 6 段:
direct-new-declarator中的表达式应具有非负值的整数或枚举类型 (3.9.1)。
- ISO/IEC 14882:2003,第 5.3.4 节,第 7 段:
当direct-new-declarator中表达式的值为零时,调用分配函数来分配一个没有元素的数组。
- ISO/IEC 14882:2003,第 5.3.4 节,第 1 段:
新表达式:
::
opt
new -placementopt
new-type-id new-initializeropt
::
opt
新 的新位置opt
( type-id )新的初始化器opt
- 尽管以上引用来自 C++03 标准,但据我所知,这个问题在 C++ 标准的较新版本(C++11、C++14 和 C++17)中仍然不清楚。
- 有趣的 Herb Sutter关于零长度数组的帖子。
- 示例中的代码是对SolidSands 的SuperTest 套件稍作修改的测试。
解决方案
使用括号,您有一个常规的type-id ,而不是称为支持动态数组大小的new-type-id的特殊语法。
从 C++17 开始,该标准没有对type-id的这种使用做出特殊规定,所以问题归结为您是否可以编写
auto main() -> int
{
using Argh = int[0];
}
你不能,因为type-id的类型是根据虚构的“省略实体名称的那种类型的变量或函数的声明”(C++17 §11.1/1)定义的,并且对于数组变量的声明,规则是“如果常量表达式 (8.20) 存在,它应该是类型的转换常量表达式std::size_t
并且它的值应该大于零”(C++17 §11.3.4/1 )。
现在对此有相当多的解释。例如,如果没有这种合理的解释,最后的引用就不能合理地说数组大小必须是非负的并且可以表示为size_t
. 相反,在没有合理解释的情况下,它会字面上说像这样的声明
int x[42];
无效(当然不是),必须表示为
int x[std::size_t(42)];
确定什么是合理的解释或过去并不容易。有人可能会问,这有意义吗?因此,对于上述情况,答案是否定的,人们可以放弃这种可能性。
然而,在某种程度上,C++14 和 C++17 越来越多,我发现早期可靠的技术失败了。但是,由于手头的问题是关于 C++03 功能的,我认为您可以相信这个答案。但是,如果这是关于 C++14 或更高版本的问题,那么请记住,任何明显明确的答案都可能涉及一些主观解释,可能无法通过询问它是否有意义来解决。
推荐阅读
- ios - 应用程序进入后台后如何继续计时器
- javascript - 表单容器输入值问题
- c++ - OPENGL 显示白框而不是可移动立方体
- objective-c - NSCollectionViewItem 不显示自定义视图
- python - 如何从 OrderedDict 中提取特定值?
- android - Android - 约束布局 - 文本和图标的对齐方式
- powerbi - Power BI - 有条件的 DistinctCount 不起作用
- reactjs - 如何在使用 map() 函数时将 this.props 从父组件传递给子组件而不会未定义?
- algorithm - 将问题划分为 n^(1/2) 个子问题的递归算法的时间复杂度
- node.js - 如何为 Node.js、express、ejs 路由构建外部 API 调用?