Strange declaration with using in C++ - c++

On a piece of code in a previous question in stackoverflow I saw this, strange to me, declaration with using:
template <std::size_t SIZE>
class A
{
public:
...
using const_buffer_t = const char(&)[SIZE];
...
};
Could someone please address the following questions:
What type it represents?
Where do we need such kind of declarations?

That's a type alias, a new syntax available since c++11.
What you're actually doing is typedefing the type of an array
const_buffer_t
will be an array of const char with length = SIZE

That using declaration is a new syntax introduced in C++11; it introduces a type alias, specifying that const_buffer_t is now an alias for the type const char(&)[SIZE]. In this respect, this use of using is substantially identical to a typedef (although using type aliases are more flexible).
As for the actual type we are talking about (const char(&)[SIZE]), it's a reference to an array of size SIZE; references to array are rarely used, but can have their use:
if in some function you want to enforce receiving a reference to an array of a specific size instead of a generic pointer, you can do that with array references (notice that even if you write int param[5] in a function declaration it's parsed as int *);
the same holds for returing references to array (documenting explicitly that you are returning a reference to an array of a specific size);
more importantly, if you want to allocate dynamically "true" multidimensional arrays (as opposed to either an array of pointers to monodimensional array or a "flat array" with "manual 2d addressing") you have to use them.
See also the array FAQ, where much of this stuff is explained in detail.

Related

If a function returns an array by reference is it a decay to pointer?

In the sample code below ComputeSomething() returns a reference to an array.
I was asked to use C++ core guidelines (NuGet package on MSVC toolchain) as an extra static analysis tool.
On the return line of ComputeSomething() the static analysis tool warns that there is an array to pointer decay. I assume the intent would be to change it in order to make the decay explicit (something like &(computed_values[0])) but then that would defeat the point of returning an array by reference.
Is this a valid warning or is it noise, for this specific use-case of returning an array by reference?
(assumes a C++98 constraint)
float (&ComputeSomething( const seed_t(&seed_data)[num_of_elems_seeded] ))[num_of_elems_calculated]{
static float computed_values[num_of_elems_calculated];
// do something...
return computed_values;
}
For the method below:
float (&ComputeSomething())[num_of_elems_calculated]{
static float computed_values[num_of_elems_calculated];
// do something...
return computed_values;
}
Unlike what is probably happening in the static analysis tool, the potential array to pointer decay is not determined inside the method but instead when the caller calls the function:
// expected to decay
float *some_computation = ComputeSomething();
// not expected to decay to pointer
float (&safer_computation)[num_of_elems_calculated] = ComputeSomething();
Thanks to #Galik for his input on this.
Yes.
In the ComputeSomething function, computed_values is an array. And as usual with arrays it can naturally decay to a pointer to its first element.
So the ComputeSomething function could be simplified to
const float* ComputeSomething(...){ ... }
To "preserve" size information, then to be able to use the function as it it now, the size needs to be known by the caller anyway. It's not something that is automatically transferred. So using a pointer will not change much, unless you absolutely want to use sizeof on the array, but that can be sidestepped by using the size you must provide in the variable declaration anyway. Using pointer will most definitely simplify the syntax, and as such also make the code more readable and maintainable.
You could also use std::vector, which have built in size information. Or force the upgrade to a more modern compiler which can use C++11, and then use std::array if you want to have compile-time fixed-size arrays.
I'm not sure if std::pair exists in C++98, or if it came in C++03, but as some kind of middle-ground you could use std::pair<float*, size_t> to return both a pointer and the size.
Then finally, you could always use typedef to create aliases to your array types. Then you don't need to explicitly specify the size everywhere, and it will simplify the syntax quite a lot:
typedef computed_values_type[num_of_elems_calculated];
....
computed_values_type& ComputeSomething(...) { ... }
...
computed_values_type& computed_values = ComputeSomething(...);
From a compiled binaries point of view, reference to an array is just the same old pointer to the first element. It differs from raw pointer only by type itself, which contains information about array size. It may be used, for instance, for compile-time size checks, compiler warnings or range-based for loop

Array template syntax outside of unique_ptr

The syntax std::unique_ptr<T[]> can be used describe the (templated) type of a unique_ptr whose underlying raw pointer is pointing to an array of Ts. I'm wondering what the syntax T[] means generally. Does it get used outside of smart pointers? Is it possible for e.g. vector<T[]> to ever be useful?
It means "array of unknown bound of T". You might see such a type in function signatures:
void f(int arr[]);
In a declaration of an array defined elsewhere:
extern int arr[];
And obviously, as a type parameter to a template like unique_ptr (or, some time in the future, shared_ptr too). It's an incomplete type, so its usefulness can be rather limited.
vector<T[]> is unlikely to be useful. If you don't know how many elements are in the array, then how could you have a container of them?

Passing array to function C++

I have one quick question about the passing of arrays in C++ which I don't understand.
Basically when you want to pass a array of type integer to another function you have to pass an address to that array instead of directly passing the whole block of contiguous memory. Exactly why is the case?
Also, why is that char arrays can directly be passed to another function in C++ without the need to pass an address instead??
I have tried looking for learning materials for this online (such as cplusplus.com) but I haven't managed to find and explanation for this.
Thanks for your time, Dan.
As long as C++ is concerned, passing char arrays and int arrays are same.
There are 2 ways to pass arrays in c++.
Address is passed
int fn(int *arrays, int len);
int fn(int arrays[], int len); // Similar to above, still staying as sytax hangover from anci c
Array reference is passed
int fn(int (&array)[SIZE]); // Actual array passed as reference
You can templatized above function as
template<size_t SIZE>
int fn(int (&array)[SIZE]);
Above method allows you to pass array of anysize to this function. But beware, a different function is created from template for each size. If your function's side effect changes a local state (static variable for ex), this should be used with care.
If you don't want to change contents, use const with arguments.
If you want a copy of array in function argument, consider using stl container like std::array or std::vector or embed array in your class.
It isn't entirely clear from your question exactly what you're trying and what problems you've had, but I'll try to give you useful answers anyway.
Firstly, what you're talking about is probably int[] or int* (or some other type), which isn't an array itself... its a pointer to a chunk of memory, which can be accessed as if it were an array. Because all you have is a pointer, the array has to be passed around by reference.
Secondly, passing around an array as a "whole block of contiguous memory" is rather inefficient... passing the point around might only involve moving a 32 or 64 bit value. Passing by reference is often a sensible thing with memory buffers, and you can explicitly use functions like memcpy to copy data if you needed to.
Thirdly, I don't understand what you mean about char arrays being "directly" passable, but other types of arrays cannot be. There's nothing magic about char arrays when it comes to passing or storing them... they're just arrays like any other. The principle difference is that compilers allow you to use string literals to create char arrays.
Lastly, if you're using C++11, you might want to consider the new std::array<T> class. It provides various handy facilities, including automatic memory management and keeping track of its own size. You can pass these by value, template<class T> void foo(std::array<T> bar) or by reference template<class T> void foo(std::array<T>& bar), as you like.
You can't pass any array by value. You can pass by value either a struct containing array or std::array from C++11.

Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?

This is what I found during my learning period:
#include<iostream>
using namespace std;
int dis(char a[1])
{
int length = strlen(a);
char c = a[2];
return length;
}
int main()
{
char b[4] = "abc";
int c = dis(b);
cout << c;
return 0;
}
So in the variable int dis(char a[1]) , the [1] seems to do nothing and doesn't work at
all, because I can use a[2]. Just like int a[] or char *a. I know the array name is a pointer and how to convey an array, so my puzzle is not about this part.
What I want to know is why compilers allow this behavior (int a[1]). Or does it have other meanings that I don't know about?
It is a quirk of the syntax for passing arrays to functions.
Actually it is not possible to pass an array in C. If you write syntax that looks like it should pass the array, what actually happens is that a pointer to the first element of the array is passed instead.
Since the pointer does not include any length information, the contents of your [] in the function formal parameter list are actually ignored.
The decision to allow this syntax was made in the 1970s and has caused much confusion ever since...
The length of the first dimension is ignored, but the length of additional dimensions are necessary to allow the compiler to compute offsets correctly. In the following example, the foo function is passed a pointer to a two-dimensional array.
#include <stdio.h>
void foo(int args[10][20])
{
printf("%zd\n", sizeof(args[0]));
}
int main(int argc, char **argv)
{
int a[2][20];
foo(a);
return 0;
}
The size of the first dimension [10] is ignored; the compiler will not prevent you from indexing off the end (notice that the formal wants 10 elements, but the actual provides only 2). However, the size of the second dimension [20] is used to determine the stride of each row, and here, the formal must match the actual. Again, the compiler will not prevent you from indexing off the end of the second dimension either.
The byte offset from the base of the array to an element args[row][col] is determined by:
sizeof(int)*(col + 20*row)
Note that if col >= 20, then you will actually index into a subsequent row (or off the end of the entire array).
sizeof(args[0]), returns 80 on my machine where sizeof(int) == 4. However, if I attempt to take sizeof(args), I get the following compiler warning:
foo.c:5:27: warning: sizeof on array function parameter will return size of 'int (*)[20]' instead of 'int [10][20]' [-Wsizeof-array-argument]
printf("%zd\n", sizeof(args));
^
foo.c:3:14: note: declared here
void foo(int args[10][20])
^
1 warning generated.
Here, the compiler is warning that it is only going to give the size of the pointer into which the array has decayed instead of the size of the array itself.
The problem and how to overcome it in C++
The problem has been explained extensively by pat and Matt. The compiler is basically ignoring the first dimension of the array's size effectively ignoring the size of the passed argument.
In C++, on the other hand, you can easily overcome this limitation in two ways:
using references
using std::array (since C++11)
References
If your function is only trying to read or modify an existing array (not copying it) you can easily use references.
For example, let's assume you want to have a function that resets an array of ten ints setting every element to 0. You can easily do that by using the following function signature:
void reset(int (&array)[10]) { ... }
Not only this will work just fine, but it will also enforce the dimension of the array.
You can also make use of templates to make the above code generic:
template<class Type, std::size_t N>
void reset(Type (&array)[N]) { ... }
And finally you can take advantage of const correctness. Let's consider a function that prints an array of 10 elements:
void show(const int (&array)[10]) { ... }
By applying the const qualifier we are preventing possible modifications.
The standard library class for arrays
If you consider the above syntax both ugly and unnecessary, as I do, we can throw it in the can and use std::array instead (since C++11).
Here's the refactored code:
void reset(std::array<int, 10>& array) { ... }
void show(std::array<int, 10> const& array) { ... }
Isn't it wonderful? Not to mention that the generic code trick I've taught you earlier, still works:
template<class Type, std::size_t N>
void reset(std::array<Type, N>& array) { ... }
template<class Type, std::size_t N>
void show(const std::array<Type, N>& array) { ... }
Not only that, but you get copy and move semantic for free. :)
void copy(std::array<Type, N> array) {
// a copy of the original passed array
// is made and can be dealt with indipendently
// from the original
}
So, what are you waiting for? Go use std::array.
It's a fun feature of C that allows you to effectively shoot yourself in the foot if you're so inclined. I think the reason is that C is just a step above assembly language. Size checking and similar safety features have been removed to allow for peak performance, which isn't a bad thing if the programmer is being very diligent. Also, assigning a size to the function argument has the advantage that when the function is used by another programmer, there's a chance they'll notice a size restriction. Just using a pointer doesn't convey that information to the next programmer.
First, C never checks array bounds. Doesn't matter if they are local, global, static, parameters, whatever. Checking array bounds means more processing, and C is supposed to be very efficient, so array bounds checking is done by the programmer when needed.
Second, there is a trick that makes it possible to pass-by-value an array to a function. It is also possible to return-by-value an array from a function. You just need to create a new data type using struct. For example:
typedef struct {
int a[10];
} myarray_t;
myarray_t my_function(myarray_t foo) {
myarray_t bar;
...
return bar;
}
You have to access the elements like this: foo.a[1]. The extra ".a" might look weird, but this trick adds great functionality to the C language.
To tell the compiler that myArray points to an array of at least 10 ints:
void bar(int myArray[static 10])
A good compiler should give you a warning if you access myArray [10]. Without the "static" keyword, the 10 would mean nothing at all.
This is a well-known "feature" of C, passed over to C++ because C++ is supposed to correctly compile C code.
Problem arises from several aspects:
An array name is supposed to be completely equivalent to a pointer.
C is supposed to be fast, originally developerd to be a kind of "high-level Assembler" (especially designed to write the first "portable Operating System": Unix), so it is not supposed to insert "hidden" code; runtime range checking is thus "forbidden".
Machine code generrated to access a static array or a dynamic one (either in the stack or allocated) is actually different.
Since the called function cannot know the "kind" of array passed as argument everything is supposed to be a pointer and treated as such.
You could say arrays are not really supported in C (this is not really true, as I was saying before, but it is a good approximation); an array is really treated as a pointer to a block of data and accessed using pointer arithmetic.
Since C does NOT have any form of RTTI You have to declare the size of the array element in the function prototype (to support pointer arithmetic). This is even "more true" for multidimensional arrays.
Anyway all above is not really true anymore :p
Most modern C/C++ compilers do support bounds checking, but standards require it to be off by default (for backward compatibility). Reasonably recent versions of gcc, for example, do compile-time range checking with "-O3 -Wall -Wextra" and full run-time bounds checking with "-fbounds-checking".
C will not only transform a parameter of type int[5] into *int; given the declaration typedef int intArray5[5];, it will transform a parameter of type intArray5 to *int as well. There are some situations where this behavior, although odd, is useful (especially with things like the va_list defined in stdargs.h, which some implementations define as an array). It would be illogical to allow as a parameter a type defined as int[5] (ignoring the dimension) but not allow int[5] to be specified directly.
I find C's handling of parameters of array type to be absurd, but it's a consequence of efforts to take an ad-hoc language, large parts of which weren't particularly well-defined or thought-out, and try to come up with behavioral specifications that are consistent with what existing implementations did for existing programs. Many of the quirks of C make sense when viewed in that light, particularly if one considers that when many of them were invented, large parts of the language we know today didn't exist yet. From what I understand, in the predecessor to C, called BCPL, compilers didn't really keep track of variable types very well. A declaration int arr[5]; was equivalent to int anonymousAllocation[5],*arr = anonymousAllocation;; once the allocation was set aside. the compiler neither knew nor cared whether arr was a pointer or an array. When accessed as either arr[x] or *arr, it would be regarded as a pointer regardless of how it was declared.
One thing that hasn't been answered yet is the actual question.
The answers already given explain that arrays cannot be passed by value to a function in either C or C++. They also explain that a parameter declared as int[] is treated as if it had type int *, and that a variable of type int[] can be passed to such a function.
But they don't explain why it has never been made an error to explicitly provide an array length.
void f(int *); // makes perfect sense
void f(int []); // sort of makes sense
void f(int [10]); // makes no sense
Why isn't the last of these an error?
A reason for that is that it causes problems with typedefs.
typedef int myarray[10];
void f(myarray array);
If it were an error to specify the array length in function parameters, you would not be able to use the myarray name in the function parameter. And since some implementations use array types for standard library types such as va_list, and all implementations are required to make jmp_buf an array type, it would be very problematic if there were no standard way of declaring function parameters using those names: without that ability, there could not be a portable implementation of functions such as vprintf.
It's allowed for compilers to be able to check whether the size of array passed is the same as what expected. Compilers may warn an issue if it's not the case.

What is the syntax for an array type?

Is it type[]? For example, could I have
T<int[]>;
for some template T.
The type of an "array of type T" is T [dimension], which is what you could pass as template parameters. E.g.:
someTemplate<int [10]> t; // array type as template parameter
int a[5]; // array of 5 ints named 'a'
Arrays need to have a dimension which must be greater than 0. This means that e.g. U u[]; is illegal.
There are cases that might seem like exceptions, the first being parameters:
void f(T[]);
This is a special rule for parameters and f() is actually equivalent to the following:
void f(T*);
Then there is direct inialization of arrays:
int a[] = { 1, 2, 3, 4 };
Here the array size is implicitly given through the number of elements in the initializer, thus the type of a is int[4].
There are also incomplete array types without specificied bounds, but you can't directly create instances of these (see Johannes answer for more):
template<class T> struct X { typedef T type; };
X<int[]>::type a = { 1, 2, 3 };
If you are looking for dynamic arrays, prefer standard containers like std::vector<T> instead.
There are two syntaxes to denote array types. The first is the type-id syntax and is used everywhere where the language expects a compile time type, which looks like:
T[constant-expression]
T[]
This specifies an array type that, in the first form, has a number of elements given by an integer constant expression (means it has to be known at compile time). In the second form, it specifies an array type with an unknown number of elements. Similar to class types that you declare without a body, such an array type is said to be incomplete, and you cannot create arrays of that type
// not valid: what size would it have?
int a[];
You can, however, specify that type. For example you may typedef it
typedef int unknown_int_array[];
In the same manner, you may specify it as a template type argument, so the answer to your question is yes you can pass such a type specifier to a template. Notice that i talk about specifiers here, because the form you use here is not the type itself.
The second way is using the new-type-id syntax which allows denoting runtime types by having non-constant bounds
T[expression]
This allows passing variables as element count, and also allows passing a zero. In such a case, a zero element array is created. That syntax is only usable with the new operator for supporting dynamic arrays.
If possible, you might consider instead using dynamic arrays, and passing in a pointer as the templated type. Such as...
T<int*> myVar;
This started as a comment to Georg's answer, but it ran a bit long...
It seems that you may be missing some key abstraction in your mental model of arrays (at least C-style ones). Local arrays are allocated on the stack with a hard-coded size. If you have an array inside a class or struct, the space for the array is part of the object itself (whether on the stack or heap). Global arrays may even be represented directly in the size of the executable.
This means that any time you want to use an array, you must specify its size to the compiler. The only reason you can leave the brackets empty in a parameter list is because functions treat array parameters as pointers. The function would hardly be useful if it could only operate on one size of array.
Templates are no exception. If you want the size of the templated array to vary, you can add an extra template parameter. You still have to specify the size at compile time for any given instance, though.
The syntax for declaring arrays is
<type> <variable>[<size>];
When using a template the declaration is, in example
template <class T>
T var[4];