“char []”是一个合适的类型吗?

时间:2015-03-20 17:21:24

标签: c++ arrays templates c++11

昨天,我很惊讶地发现了一些似乎将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[]

3 个答案:

答案 0 :(得分:4)

  

char[]在C ++中实际意味着什么?

让我们找出:

  

[C++11: 8.3.4/1]:T D声明中D的格式为

     

D1 [ 常量表达式 opt ] attribute-specifier-seq opt

     

并且声明T D1中的标识符类型是“ derived-declarator-type-list T”,然后是{{1的标识符的类型是一个数组类型;如果D的标识符类型包含D 类型说明符,则程序格式错误。 auto称为数组元素类型;此类型不应是引用类型,(可能是cv限定的)类型T,函数类型或抽象类类型。如果存在常量表达式(5.19),则它应为整数常量表达式,其值应大于零。常量表达式指定数组中(元素数量)的 bound 。如果常量表达式的值为void,则数组具有编号为NN的{​​{1}}个元素,0的标识符类型为“ {em> derived-declarator-type-list N-1“数组。数组类型的对象包含D类型的N T子对象的连续分配的非空集。除非另有说明,否则如果省略常量表达式,则N的标识符类型为“ derived-declarator-type-list 未知范围{{1}的数组“,一个不完整的对象类型。类型“ derived-declarator-type-list T”类型与“ 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.