I have a corner case with regards to pointers and arrays.
How do I allocate a fixed-size (automatic) array on the heap? Let's get to the code right away to understand what I'm trying to ask:
typedef int ArrayOf10Ints[10];
int f()
{
ArrayOf10Ints * p = new ArrayOf10Ints; // Error: cannot initialize a variable of type 'ArrayOf10Ints *'
// (aka 'int (*)[10]') with an rvalue of type 'int *'
ArrayOf10Ints * q = new ArrayOf10Ints[1] // OK: allocates space for 10 ints
delete q; // Warning: use delete []
}
Why doesn't the expression to allocate p work? Why is the rvalue an int* and not a ArrayOf10Ints*? And why does q work?
Note: my goal is to understand the unexpected behavior allocating p and q. As others have pointed out there are many straightforward ways to solve this problem. For example, in my case, I'm using a pointer to denote that the array is optional—it may or may not exist—so I would do this instead:
boost::optional<std::array<int, 10> > optional_array;
This is a behavior of new that is somewhat surprising. Even though ArrayOf10Ints is an alias for int[10], when you use it in a new expression, the result is as if you were writing new int[10] instead.
This is specified in [expr.new]/5
When the allocated object is an array (that is, the noptr-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array.
So in your example, the new expression returns an int *, hence the error.
A workaround is to do what you've shown
ArrayOf10Ints* q = new ArrayOf10Ints[1];
delete[] q;
or place the array in a struct, or use std::array.
Note that even if you were to write
int* p = new ArrayOf10Ints;
you must then use delete[] p because operator new[] is called in this case too.
Live demo
Note: for reasons beyond this discussion, I need to do exactly this
Certainly not, because wrong things don't work.
Use a std::array<int,10> instead. This code should work just smoothly:
typedef array<int,10> ArrayOf10Ints;
int f() {
ArrayOf10Ints * p = new ArrayOf10Ints;
// ...
delete p;
}
However I won't recommend you manage new and delete yourself, unless you're absolutely sure you need to.
Related
I am puzzled how both new int and new int[n] return an int*. Why doesn't the latter return an int**?
Here is some context: refer to the variable data below in a snippet from Goodrich, Tamassia, and Mount's 2nd ed. Data Structures and Algs in C++ textbook:
class Vect {
public:
Vect(int n);
~Vect();
// ... other public members omitted
private:
int* data;
int size;
};
Vect::Vect(int n) {
size = n;
data = new int[n];
}
Vect::~Vect() {
delete [] data;
}
(answers contains simplifications for the sake of explanations)
In C, a pointer to an array of ints would be of type int**, if I am not mistaken.
You are mistaken. In C it also would be int*, more precisely: int (*)[]
When you declare: int foo[] = { 1, 2, 3 }, the name of array (foo) can be in many cases effectively treated as pointer to its first element (1). The pointer to int is int*.
Additionally, why are we calling delete[] instead of delete, to delete an int* (data)?
delete deletes single object. delete [] removes dynamic array.
new int[n] cannot return a result of type int** because an int** value has to point to an object of type int* (a pointer object).
new int[n] allocates memory for an array of n objects, each of which is of type int. It does not create a pointer object.
The int* value it returns points to the initial (0th) element of the allocated array. Other elements of the array can be accessed by pointer arithmetic.
It could have been defined to yield a result of type int (*)[n], which is a pointer to an array of n int elements, except that (a) C++ doesn't permit arrays with non-constant bounds, and (b) even for something like int (*)[4], it's less convenient that int*.
C++, like its ancestor language C, treats arrays as second-class citizens. Array expressions, in most but not all contexts, are "converted" (adjusted at compile time) to pointer expressions, pointing to the initial element of the array object, and array elements are accessed using pointer arithmetic. (The indexing operator a[i] is syntactic sugar for *(a+i)).
Yes, it can all be confusing and counterintuitive.
Recommended reading: Section 6 of the comp.lang.c FAQ (most of it applies to both C and C++).
#include <memory>
int main()
{
std::shared_ptr<double> array (new double [256], [](double * d){
delete [] d;
});
}
I made a shared_ptr pointing into an array of doubles which has its own custom deleter.
Now how can I access the array? Let's say I wish to access the array at index 1. I tried the usual "bracket method" but I get errors.
The word array points to its first element by default, but what if I want to access the 2nd element? Using increments and bracket gives me the "no match for operator" error.
Can someone explain to me what's happening under the hood?
I am asking this for research purposes, despite being aware that unique_ptr and vector will do a better job.
The bracket notation is defined to work with pointer types (and you're right that, given array array, the expression array decays to an expression with such a type which points to the first element) but, despite its function, std::shared_ptr is not a pointer type.
You would have to obtain the raw pointer first:
array.get()[n];
Where n is, of course, a valid array subscript.
This is also the case with std::unique_ptr (though note that, in that case, you do not need to supply your own deleter!).
in C++17, support for array of shared_ptr like in unique_ptr( c++11).
int main()
{
std::shared_ptr<double[]> array1 (new double [3]{4,5,6}, [](double * d){
delete [] d;});
std::unique_ptr<double[]> array2 (new double [3]{4,5,6}, [](double * d){
delete [] d });
}
Why is
int *a = new int[10];
written as
int *a;
a = new int[10];
instead of
int *a;
*a = new int[10];
?
The way I see it, in the second block of code you're saying a, which was a pointer variable, is now an array. In the third block of code you're saying the thing a points to is now an array. Why does the second make more sense than the third?
new int[10] returns a pointer to the first element in the array (which is of type int*). It does not return a pointer to the array (which would be of type int(*)[10]).
a = new int[10] means make a point to the first element of the dynamically allocated array. *a is not a pointer at all. It is the object pointed to by the pointer a (which is of type int).
Note that if you actually had a named array object, the syntax would still be the same:
int x[10];
int* a = x;
Why? In C++, in most cases, whenever you use an array, it is implicitly converted to a pointer to its initial element. So here, int* a = x is the same as int* a = &x[0];.
(There are several cases where the array-to-pointer decay does not occur, most notably when the array is the operand of the & or sizeof operators; they allow you to get the address of the array and the size of the array, respectively.)
*a = ... means assign value to memory that I'm pointing to
a = ... means assign me new memory address that I should point to
The type int* is a pointer to an int. If you apply the derefence operator to such a pointer, you get an int (or, more precisely, actually a reference to an int, i.e. a int&) That is, when you write
int* a;
*a = new int[10]; // ERROR: incompatible types `int&` and `int*`
you try to assign the result of new int[10] which is of type int* to an object of type int&. This isn't supposed to work.
In the third block of code you're saying the thing a points to is now an array.
You're not, though.
new doesn't evaluate to an array, but to a pointer to a block of memory. That's why you're assigning to a pointer.
It's a consequence of dynamically-allocated objects not being directly reachable in the current lexical scope.
Because this :
a = new int[10];
and this :
*a = new int[10];
are completely different things. The 2nd is the pointer dereferencing.
This:
int *a = new int[10];
and this
int *a;
a = new int[10];
are same things.
You are assigning to a pointer variable, so you have to write a.
Would you have written
int* a = new int[10];
this would be more obvious that the type of a is int* (pointer to an `int).
Because operator new returns the address of the object(s) it creates. *a is not an address, it's the int that a points at.
When you declare a pointer,
int *a;
in the memory:
Memory Address Variable Identifier Variable Value
-------------- -------------- --------------
0xAE934904 a ?
When you create a dynamic array, you have 10 integer numbers:
a = new int[10];
Memory Address Variable Identifier Variable Value
-------------- -------------- --------------
0xH3948300 - ?
0xH3948304 - ?
0xH3948308 - ?
0xH394830C - ?
...
(in total, 10 integers) and value of a becomes 0xH3948300.
Memory Address Variable Identifier Variable Value
-------------- -------------- --------------
0xAE934904 a 0xH3948300
On the other hand, if you write *a = new int[10]; this is *(?) which means go to the value that is stored at memory location ?. *(?) is probably not a memory space where you can store memory address. If you want to assign a value to the pointer, you simply type the identifier name, a.
Note: I am using the g++ compiler (which is I hear is pretty good and supposed to be pretty close to the standard).
Let's say you have declared an array of ints:
int a[3] = { 4, 5, 6 };
Now let's say you really want to declare a reference to that array (nevermind why, other than the Bjarne says the language supports it).
Case 1 -- If you try:
int*& ra = a;
then the compiler balks and says:
"invalid initialization of non-const reference of type `int*&' from a temporary of type `int*'"
First things first, why is 'a' a temporary variable (i.e. doesn't it have a place in memory?)...
Anyway, fine, whenever I see a non-const error, I try to throw in a const...
Case 2 -- if you try:
int*const&rca = a; //wish I knew where the spaces should go (but my other post asking about this sort of protocol got a negative rank while many of the answers got ranked highly -- aha! there are stupid questions!)
Then everything is cool, it compiles, and you get a reference to the array.
Case 3 -- Now here is another thing that will compile:
int* justSomeIntPointer = a; //LINE 1
int*& rpa = justSomeIntPointer; //LINE 2
This also gives you a reference to the original array.
So here is my question: At what point does the name of a statically declared array
become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...
It seems like Case 1 fails because the reference declared (ra) is not to a const-pointer, which may mean that 'a' was already a const-pointer-to-int to begin with.
It seems like Case 2 works because the reference declared (rca) is already a const-pointer-to-int.
Case 3 also works, which is neat, but why? At what point does the assumed pointer-to-int (i.e. the array name 'a') become a const-pointer? Does it happen when you assign it to an int* (LINE 1), or does it happen when you assign that int* to a int*& (LINE 2)?
Hope this makes sense. Thanks.
int*& ra = a;
int* is a pointer type, not an array type. So that's why it won't bind to a, which has type int[3].
int* const& ra = a;
works, because it is equivalent to
int* const& ra = (int*)a;
That is, a temporary pointer is conceptually created on the right-hand side of the assignment and this temporary is then bound to ra. So in the end, this is no better than:
int* ra = a;
where ra is in fact a pointer to the first element of the array, not a reference to the array.
Declaring a reference to an array the easy way:
typedef int array_type[3];
array_type& ra = a;
The not-as-easy way:
int (&ra)[3] = a;
The C++11-easy way:
auto& ra = a;
At what point does the name of a statically declared array become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...
This is the right question to ask! If you understand when array-to-pointer decay happens, then you're safe. Simply put there are two things to consider:
decay happens when any kind of 'copying' is attempted (because C doesn't allow arrays to be copied directly)
decay is a kind of conversion and can happen anytime a conversion is allowed: when the types don't match
The first kind typically happen with templates. So given template<typename T> pass_by_value(T);, then pass_by_value(a) will actually pass an int*, because the array of type int[3] can't be copied in.
As for the second one, you've already seen it in action: this happens in your second case when int* const& can't bind to int[3], but can bind to a temporary int*, so the conversion happens.
The word "array" in C++ is spelled with brackets []. If you want to declare a something-array-something in C++, you have to have brackets in your declaration. If you write an asterisk * instead, you will get a pointer. Pointers and arrays are two different things.
This is a reference to an array:
int (&ra) [3] = a;
The very big mistake (also a very good interview question) that most people make is that they think the name of an array is equivalent to a pointer. That is NOT true. This mistake causes many bugs in C programs especially linking bugs, and they are very hard to debug. The diffrence is this: The name of the array, is a pointer the first element of a structure, the array. The type of the array name is not a pointertype however, but an arraytype. A pointer, on the other hand, is just a pointer to one thing with no other information. The type of a pointer is a pointertype. An arraytype has some other properties like it knows whether its on the stack or not; therefore, "temporary". The temporary error in your case comes from a check that prevents a temporary variable to be assigned to a reference. The const keyword turns that check off. A pointertype on the other hand has no notion of "temporary". Now suppose you want to trick the compiler and assign a reference to something that is in the stack. In that case, you need to make it a pointer. How?
int*& ra = &a[0];
in the above case you first get the value and using a &(address of operator) you make a pointerType. Now a pointertype has no information about whether its on the stack (a temporary variable) or not. This however, will make a reference to a pointer to the first element of the array. (Therefore just a pointer type, not an arraytype)
If you really want a reference to an array, then you should use the following:
int a[3] = { 4, 5, 6 };
int (&ra)[3] = a;
What you are trying to create with int *& is a reference to a pointer to an int. This is not the same type. And as you initialize the reference with a value that cannot change (the address of the array) you have to declare the pointer const (not the ints).
You have an array of ints :
int a[3] = { 4, 5, 6 };
Now, this line :
int*& ra = a;
creates a reference to a pointer. Since you create a temporary pointer (converted from the array a), the compiler complains, because the standard forbids assignment of temporaries to a reference.
So, to fix it, you need to create a pointer, and then assign it to a reference to a pointer :
int *pa = a;
int *& rpa = pa;
Constant references can hold reference to temporaries, but you already found that out.
What you asked (about reference to an array) - the most famous example about creating a reference to an array is this :
template< typename T, size_t N >
size_t ArraySize( T (&)[ N ] )
{
return N;
}
This function takes a reference to an array, and returns it's size.
At what point does the name of a statically declared array become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...
Because you written the values right there in the cpp file, that's why it's constant.
You can just use:
const int *pToArray = a;
or
const int *pToArray = (const int*)&a[0];
a is a temporary variable because you declared it on the stack and not on the heap using a malloc or a new.
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);
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];
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>();
}
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]