First of all, I want to reassure you all that I am asking this question out of curiosity. I mean, don't tell me that if I need this then my design has problems because I don't need this in real code. Hope I convinced you :) Now to the question:
For most types T we can write
T* p = new T;
now what if T is an array type?
int (*p)[3] = new ???; //pointer to array of 3 = new ???
I tried this:
typedef int arr[3];
arr* p = new arr;
but this doesn't work.
Is there any valid syntax for this or it is impossible in C++. If it is impossible, then why? Thanks
Edit: i am guessing I wasn't clear enough. I want to be able to use it in this situation:
void f(int(&)[3]);
int (*p)[3] = new ???;
f(*p);
The reason you can't do it is that new int[3]
already allocates exactly what you want, an object of type int[3]
. It's just that what the new-expression returns, is a pointer to its first element. 5.3.4/1:
If the entity is a non-array object,
the new-expression returns a pointer
to the object created. If it is an
array, the new-expression returns a
pointer to the initial element of the
array.
Returning a pointer to the first element is what allows the 3
to be unknown until runtime, so I suppose that by knowing it in advance, you've tripped over flexibility that you aren't using.
I guess the ways around this are to reinterpret_cast back to the pointer type you want (not necessarily portable), or to allocate a struct containing an int[3]
(and use a pointer to its data member).
[Edit: er, yeah, or FredOverflow's idea, which has neither disadvantage, but requires use of delete[]
instead of delete
.]
I guess the moral is, if you write templates that naively allocate some unknown type T
with new
, then the template won't work when someone passes an array type as T
. You'll be assigning it to the wrong pointer type, and if you fix that (perhaps with auto
), you'll be deleting it wrongly.
Edit in answer to j_kubik's question:
Here's one way to distinguish between array and non-array types. If you write a function like this, that returns an object that holds the pointer and is capable of correctly deleting it, then you have a generic new/delete for any type T.
#include <iostream>
template <typename T>
void make_thing_helper(T *) {
std::cout << "plain version\n";
}
template <typename T, int N>
void make_thing_helper(T (*)[N]) {
std::cout << "array version\n";
}
template <typename T>
void make_thing() {
make_thing_helper((T*)0);
}
int main() {
typedef int T1;
typedef int T2[3];
make_thing<T1>();
make_thing<T2>();
}
To get a pointer to an array from new
, you have to dynamically allocate a two-dimensional array:
int (*p)[3] = new int[1][3];
You could always use boost::array, which will be in C++0x.
Otherwise, any solution will be awkward at best: arrays are
broken in C, and C++ maintains compatilibity with C in this
respect. Fred Overflow offered one solution; even easier (but
syntactically noisy) would be to wrap the array in a struct:
struct A { int arr[3]; };
and allocate and manipulate this.
You just do
int *p = new unsigned int [3]
You can then use *p
as a pointer or an array i.e. *(p+1) or p[1]