昨天,我很惊讶地发现了一些似乎将char[]
视为一种类型的代码:
typedef std::unique_ptr<char[]> CharPtr;
以前,我会写一些类似的东西:
typedef std::unique_ptr<char*, CharDeleter> CharPtr;
// Custom definition of CharDeleter omitted
经过一些研究,我发现char[]
语法有效,因为std::unique_ptr
提供了一个模板专门化来处理数组(例如,它会自动为数组调用delete[]
,而不需要自定义删除器)
但是char[]
在C ++中实际意味着什么?
我看过如下语法:
const char a[] = "Constant string"; // Example 1
char *p = new char[5]; // Example 2
bool foo(char param[10]); // Example 3
这就是我解释这些例子的方式:
示例1分配一个静态数组(在堆栈上)并且空索引是有效的,因为字符串的真实大小在编译时是已知的(例如,编译器基本上是在幕后处理我们的长度)
示例2动态分配5个连续字符,第一个字符存储在p中存储的地址。
示例3定义了一个函数,该函数将大小为10的数组作为参数。 (在后台,编译器将数组视为指针) - 例如这是一个错误:
void foo(char test[5]) {}
void foo(char * test) {}
因为函数签名对编译器来说是不明确的。
我觉得我理解数组/指针的差异和相似之处。我的困惑可能源于我缺乏构建/阅读C ++模板的经验。
我知道模板专门化基本上允许根据模板类型参数使用自定义模板(基于特定模板)。 char[]
只是一种可用于模板特化的语法(调用特定的特化)吗?
此外,数组&#34;类型&#34;的正确名称是什么?比如char[]
?
答案 0 :(得分:4)
char[]
在C ++中实际意味着什么?
让我们找出:
[C++11: 8.3.4/1]:
在T D
声明中D
的格式为
D1 [
常量表达式 opt]
attribute-specifier-seq opt并且声明
T D1
中的标识符类型是“ derived-declarator-type-listT
”,然后是{{1的标识符的类型是一个数组类型;如果D
的标识符类型包含D
类型说明符,则程序格式错误。auto
称为数组元素类型;此类型不应是引用类型,(可能是cv限定的)类型T
,函数类型或抽象类类型。如果存在常量表达式(5.19),则它应为整数常量表达式,其值应大于零。常量表达式指定数组中(元素数量)的 bound 。如果常量表达式的值为void
,则数组具有编号为N
到N
的{{1}}个元素,0
的标识符类型为“ {em> derived-declarator-type-listN-1
“数组。数组类型的对象包含D
类型的N T
子对象的连续分配的非空集。除非另有说明,否则如果省略常量表达式,则N
的标识符类型为“ derived-declarator-type-list 未知范围{{1}的数组“,一个不完整的对象类型。类型“ derived-declarator-type-listT
”类型与“ derived-declarator-type-list 未知数组类型不同D
“的界限,见3.9。 [..]
正如您所指出的那样,这些“未知界限数组”正在通过T
专业化使用。
关于示例1,虽然在N T
中出人意料地不清楚,但T
初始化是一个特殊情况,上面的文字未涵盖:std::unique_ptr
实际上是{{1} }}。所以,是的,“编译器基本上是在幕后处理我们的长度”。
示例3定义了一个函数,该函数将大小为10的数组作为参数。 (在后台,编译器将数组视为指针)
几乎。事实上,没有任何关于它的“幕后”:转换是在手册中。它是前沿和中心,明确和标准化。
所以:
- 例如这是一个错误:
[C++11: 8.5.5]
因为函数签名对编译器来说是不明确的。
事实上,这不是通过“歧义”而是错误,而是因为你确实两次定义了相同的函数。
答案 1 :(得分:3)
char[]
是一种类型,但是您不能拥有实例的类型。它是一种不完整的对象类型,有点像struct foo;
。
这意味着如果模板选择,模板可以使用char[]
作为类型。他们无法创建char[]
类型的变量,但它们可以与类型进行交互。
现在,从C继承的数组附加了一堆“魔法”行为。作为函数参数参数,char[]
变为char*
(char[33]
也是如此!)
作为局部变量,char x[]="foo";
或char y[]={'a','b','c'};
成为固定大小的数组。这里,char[]
表示“自动调整数组大小”。
从某种意义上说,这些都是参数类型和变量声明中的怪癖,而不是类型的怪癖。您声明的类型与您声明的类型看起来并不那么相似。
还有一些涉及类型衰减的奇怪 - 像char[3]
这样的char x[3];
类型的变量会在降低时衰减到char*
。这与自动调整大小的数组非常相似,基本上是C的遗产。
标准中明确描述了所有这些,但由于它与大多数“常规”类型有很大不同,因此它就像魔术一样。
毕竟,标准中任何足够迟钝的特征都与魔法无法区分。
答案 2 :(得分:2)
是的,char[]
表示char
&#34;的未知界限的复合类型&#34;数组。这是一个不完整的类型,但可以在以后完成:
extern char a[]; // "a" has incomplete type at point of declaration
char a[10]; // Now "a" has complete type.