Is "char []" the correct type?

Yesterday I was surprised to find some code that seemed to consider char[] as a type:

 typedef std::unique_ptr<char[]> CharPtr; 

I would write something like:

 typedef std::unique_ptr<char*, CharDeleter> CharPtr; // Custom definition of CharDeleter omitted 

After some research, I found that the char[] syntax works, because std::unique_ptr provides a specialized specialization for processing arrays (for example, it will automatically call delete[] on the array without the need for user deletion)

But what does char[] really mean in C ++?

I saw syntax like:

 const char a[] = "Constant string"; // Example 1 char *p = new char[5]; // Example 2 bool foo(char param[10]); // Example 3 

Here is how I interpret these examples:

Example 1 allocates a static array (on the stack), and empty indexes are valid, since the true size of the string is known at compile time (for example, the compiler basically handles the length for us behind the scenes)

Example 2 dynamically allocates 5 adjacent characters, with the first character stored at the address stored in p.

Example 3 defines a function that takes an array of size 10 as a parameter. (Behind the scenes, the compiler treats the array as a pointer) - for example. this is mistake:

 void foo(char test[5]) {} void foo(char * test) {} 

because function signatures are ambiguous for the compiler.

It seems to me that I understand the differences between arrays and pointers and their similarities. My confusion probably stems from my lack of experience creating / reading templates in C ++.

I know that specializing a template basically allows you to use a custom template (based on a specific template) depending on the parameters of the template type. Is char[] just a syntax available for template specialization (invoking a specific specialization)?

Also, what is the name for the types array, for example char[] ?

+7
c ++ arrays c ++ 11 templates
source share
3 answers

What does char[] mean in C ++?

Find out:

[C++11: 8.3.4/1]: In a TD declaration, where D is of the form

D1 [ constant expression opt ] attribute-specifier-seq opt

and the identifier type in the declaration of T D1 is "derived-declarator-type-list T ", then the identifier type D is an array type; if the identifier type D contains an auto type specifier, the program is poorly formed. T is called the type of the element of the array; this type should not be a reference type, type (possibly cv-qualit) void , type of function, or type of abstract class. If the constant expression (5.19) is present, it must be an integral constant expression, and its value must be greater than zero. A constant expression defines the boundary (number of elements in) of the array. If the value of the constant expression is N , the array has N elements numbered 0 to N-1 , and the identifier type D is an array from an NT -type declarative derivative. An array type object contains a contiguous non-empty set of N subobjects of type T Except, as indicated below, if the constant expression is omitted, the identifier type D is an "array of derived-declarator-list-type of unknown boundary T ", an incomplete object type . The type "array-declarator-type-list-list-array of NT " is it is another type of type "array-declarator-type-list-array" with unknown boundary T ", see 3.9. [..]

As you point out, these “arrays of unknown boundaries” are used with the specialization std::unique_ptr .

In relation to example 1, although in [C++11: 8.5.5] char[] unexpectedly unclear, there is a special case with the initializer that is not covered by the above text: a actually a const char[16] . So yes, "the compiler basically handles the length for us backstage."


Example 3 defines a function that takes an array of size 10 as a parameter. (Behind the scenes, the compiler treats the array as a pointer)

Nearly. In fact, there is nothing "behind the scenes" in it: the conversion is in the brochure. It is front and center, explicit and standardized.

So:

- eg. this is mistake:

 void foo(char test[5]) {} void foo(char * test) {} 

because function signatures are ambiguous for the compiler.

Actually, this is not a mistake through "ambiguity", but because you literally defined the same function twice.

+4
source share

char[] is a type, but a type in which you cannot have an instance. This is an incomplete object type, somewhat similar to struct foo; .

This means that patterns can consume char[] as a type if they want to. They cannot create a variable of type char[] , but they can interact with the type.

Now there is a bunch of "magic" behavior associated with arrays inherited from C. The char* function parameter becomes char* (like char[33] !)

As a local variable, char x[]="foo"; or char y[]={'a','b','c'}; becomes an array of fixed size. Here, char[] means "array auto-size".

In a sense, these are both quirks in parameter types and variable declarations, not quirks of this type. The type you declare does not look like the type you declare.

There are also many oddities associated with type decay — a variable of type char[3] , similar to char x[3]; will drop to char* when the hat falls. This, like automatic arrays, is mostly a legacy of C.

All of this is explicitly described in the standard, but since it differs significantly from most "ordinary" types, it acts like magic.

In the end, any rather dumb feature of the standard is indistinguishable from magic.

+3
source share

Yes, char[] denotes the complex type "array of unknown boundary char ". This is an incomplete type, but one that can be completed later:

 extern char a[]; // "a" has incomplete type at point of declaration char a[10]; // Now "a" has complete type. 
+2
source share

All Articles