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?
Related
I have this pair of declaration/definition on my Eclipse IDE (in a .h and .hpp respectively):
A( T* [] );
and
A<T>::A(T ** p_proc) { ... }
The first is an array of pointers, the other a pointer of pointers.
I am confused in that they are interchangeable here; Eclipse complains if I replace the ** by * [], throwing a syntax error. Eclipse does not raise errors when I do the opposite, though.
My question is twofold; are these two notations fundamentally the same? Are T [][] and T ** the same as well?
Why does Eclipse throw a syntax error when the hpp file has a type of * [], but not in the header?
My question is twofold; are these two notations fundamentally the same?
No, they are not. T*[] has type array of unknown size of pointer to T whereas T** has type pointer to pointer to T. Arrays and pointers are not identical in general.
However, declaring a function parameter to be of array type is exactly the same as declaring it to be of the corresponding pointer type. If a function parameter is specified to have array type then it's "adjusted" to have the corresponding pointer type. In the same way, int* and int[] aren't the same type, but when you write a function that takes an int[] parameter, it's adjusted so that it takes an int* parameter. (Note that this adjustment is suppressed if the parameter is a reference to array.)
Are T [][] and T ** the same as well?
Actually T[][] is not a valid type at all. In a multidimensional array type, only the first bound may be omitted.
Why does Eclipse throw a syntax error when the hpp file has a type of * [], but not in the header?
Probably because you're writing T*[] p_proc. The correct declarator is T* p_proc[].
They're the same for parameters to functions. A function parameter can't have the type "array of T". If you try to declare a function parameter as having a type "array of T", the compiler will (silently) adjust it to "pointer to T".
That's not the case elsewhere though. Just for example, having something like:
//filea.cpp
int x[SIZE];
and:
//fileb.cpp
extern int *x;
...will not work.
If your Eclipse is not understanding the following case, it's a bug:
template<typename T>
struct A{
A(T **p_proc);
};
template<typename T>
A<T>::A(T *p_proc[]) {}
It's perfectly fine.
Check question about arrays decaying to pointers to understand it in more detail.
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.
Why can't you pass arrays as function arguments?
I have been reading this C++ book that says 'you can't pass arrays as function arguments', but it never explains why. Also, when I looked it up online I found comments like 'why would you do that anyway?' It's not that I would do it, I just want to know why you can't.
Why can't arrays be passed as function arguments?
They can:
void foo(const int (&myArray)[5]) {
// `myArray` is the original array of five integers
}
In technical terms, the type of the argument to foo is "reference to array of 5 const ints"; with references, we can pass the actual object around (disclaimer: terminology varies by abstraction level).
What you can't do is pass by value, because for historical reasons we shall not copy arrays. Instead, attempting to pass an array by value into a function (or, to pass a copy of an array) leads its name to decay into a pointer. (some resources get this wrong!)
Array names decay to pointers for pass-by-value
This means:
void foo(int* ptr);
int ar[10]; // an array
foo(ar); // automatically passing ptr to first element of ar (i.e. &ar[0])
There's also the hugely misleading "syntactic sugar" that looks like you can pass an array of arbitrary length by value:
void foo(int ptr[]);
int ar[10]; // an array
foo(ar);
But, actually, you're still just passing a pointer (to the first element of ar). foo is the same as it was above!
Whilst we're at it, the following function also doesn't really have the signature that it seems to. Look what happens when we try to call this function without defining it:
void foo(int ar[5]);
int main() {
int ar[5];
foo(ar);
}
// error: undefined reference to `func(int*)'
So foo takes int* in fact, not int[5]!
(Live demo.)
But you can work-around it!
You can hack around this by wrapping the array in a struct or class, because the default copy operator will copy the array:
struct Array_by_val
{
int my_array[10];
};
void func (Array_by_val x) {}
int main() {
Array_by_val x;
func(x);
}
This is somewhat confusing behaviour.
Or, better, a generic pass-by-reference approach
In C++, with some template magic, we can make a function both re-usable and able to receive an array:
template <typename T, size_t N>
void foo(const T (&myArray)[N]) {
// `myArray` is the original array of N Ts
}
But we still can't pass one by value. Something to remember.
The future...
And since C++11 is just over the horizon, and C++0x support is coming along nicely in the mainstream toolchains, you can use the lovely std::array inherited from Boost! I'll leave researching that as an exercise to the reader.
So I see answers explaining, "Why doesn't the compiler allow me to do this?" Rather than "What caused the standard to specify this behavior?" The answer lies in the history of C. This is taken from "The Development of the C Language" (source) by Dennis Ritchie.
In the proto-C languages, memory was divided into "cells" each containing a word. These could be dereferenced using the eventual unary * operator -- yes, these were essentially typeless languages like some of today's toy languages like Brainf_ck. Syntactic sugar allowed one to pretend a pointer was an array:
a[5]; // equivalent to *(a + 5)
Then, automatic allocation was added:
auto a[10]; // allocate 10 cells, assign pointer to a
// note that we are still typeless
a += 1; // remember that a is a pointer
At some point, the auto storage specifier behavior became default -- you may also be wondering what the point of the auto keyword was anyway, this is it. Pointers and arrays were left to behave in somewhat quirky ways as a result of these incremental changes. Perhaps the types would behave more alike if the language were designed from a bird's-eye view. As it stands, this is just one more C / C++ gotcha.
Arrays are in a sense second-class types, something that C++ inherited from C.
Quoting 6.3.2.1p3 in the C99 standard:
Except when it is the operand of the sizeof operator or the unary
& operator, or is a string literal used to initialize an array, an
expression that has type "array of type" is converted to an
expression with type "pointer to type" that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
The same paragraph in the C11 standard is essentially the same, with the addition of the new _Alignof operator. (Both links are to drafts which are very close to the official standards. (UPDATE: That was actually an error in the N1570 draft, corrected in the released C11 standard. _Alignof can't be applied to an expression, only to a parenthesized type name, so C11 has only the same 3 exceptions that C99 and C90 did. (But I digress.)))
I don't have the corresponding C++ citation handy, but I believe it's quite similar.
So if arr is an array object, and you call a function func(arr), then func will receive a pointer to the first element of arr.
So far, this is more or less "it works that way because it's defined that way", but there are historical and technical reasons for it.
Permitting array parameters wouldn't allow for much flexibility (without further changes to the language), since, for example, char[5] and char[6] are distinct types. Even passing arrays by reference doesn't help with that (unless there's some C++ feature I'm missing, always a possibility). Passing pointers gives you tremendous flexibility (perhaps too much!). The pointer can point to the first element of an array of any size -- but you have to roll your own mechanism to tell the function how big the array is.
Designing a language so that arrays of different lengths are somewhat compatible while still being distinct is actually quite tricky. In Ada, for example, the equivalents of char[5] and char[6] are the same type, but different subtypes. More dynamic languages make the length part of an array object's value, not of its type. C still pretty much muddles along with explicit pointers and lengths, or pointers and terminators. C++ inherited all that baggage from C. It mostly punted on the whole array thing and introduced vectors, so there wasn't as much need to make arrays first-class types.
TL;DR: This is C++, you should be using vectors anyway! (Well, sometimes.)
Arrays are not passed by value because arrays are essentially continuous blocks of memmory. If you had an array you wanted to pass by value, you could declare it within a structure and then access it through the structure.
This itself has implications on performance because it means you will lock up more space on the stack. Passing a pointer is faster because the envelope of data to be copied onto the stack is far less.
I believe that the reason why C++ did this was, when it was created, that it might have taken up too many resources to send the whole array rather than the address in memory. That is just my thoughts on the matter and an assumption.
It's because of a technical reason. Arguments are passed on the stack; an array can have a huge size, megabytes and more. Copying that data to the stack on every call will not only be slower, but it will exhaust the stack pretty quickly.
You can overcome that limitation by putting an array into a struct (or using Boost::Array):
struct Array
{
int data[512*1024];
int& operator[](int i) { return data[i]; }
};
void foo(Array byValueArray) { .......... }
Try to make nested calls of that function and see how many stack overflows you'll get!
I'd like to declare a member function pointer in C++, that returns the same member function pointer type
This doesn't work:
class MyClass {
public:
typedef FunctionPtr (MyClass::*FunctionPtr)();
}
Does someone know a solution?
There's no way to achieve exactly that. In fact, member functions make no difference here: there's no way to declare an ordinary function that returns a pointer to its own function type. The declaration would be infinitely recursive.
In case of an ordinary function you can use the void (*)() type as an "universal" function pointer type (just like void * is often used for data types). For member function pointers that would be void (A::*)() type. You'd have to use reinterpret_cast for that purpose though. However, this usage (a round-trip conversion) happens to be the one when the behavior of reinterpret_cast is defined.
Of course, you'll be forced to use casts to convert the pointer to and from that type. AFAIK, there are elegant template-based solutions with an intermediate temporary template object that does the casting.
You might also want to take a look at this GotW entry.
P.S. Note, that using void * type as an intermediate type for function pointers is prohibited by the language. While such illegal use might appear to be "working" with ordinary function pointers, it has absolutely no chance to work with member function pointers. Member function pointers are normally non-trivial objects with size greater than the size of void * pointer.
AndreyT references the best answer at GotW #57, so I might as well replicate it here:
class MyClass {
public:
struct FunctionPtrProxy;
typedef FunctionPtrProxy (MyClass::*FunctionPtr)();
struct FunctionPtrProxy
{
FunctionPtrProxy(FunctionPtr pp ) : p( pp ) { }
operator FunctionPtr() { return p; }
FunctionPtr p;
}
}
What you're trying to do is not possible - the return type of the function is the type of the function itself, which is not yet known, so it leads to an infinite cycle.
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];