Array with size 0 Has good explanations of zero-length arrays and is certainly worthwhile and pertinent. I am not seeing it compare zero-length with single-element arrays and with pointer-to-variable.
When I asked before (Is c++ delete equivalent to delete[1]?) I did not express myself well. My question seemed to be the same or included in more general answers about new, new[], delete, and delete[]. Some understood that I was asking only about a single element. All answers in comments seemed correct and consistent.
There is a question that looks like the same as this question. But the body is about using C++ and Java together. Here, we are talking only about C++.
Checking my understanding
I will present pairs of proposed equivalent statements. The statements are declarations or instantiations of a pointer to a single variable followed by a pointer to an array of one element. Then I will state why I would think they are equivalent or not.
Are these pairs equivalent?
int one = 1;
// Sample 1. Same in the sense of pointing to an address somewhere
// whose contents equal one. Also same in the sense of not being able to
// change to point to a different address:
int * const p_int = &one;
int a_int[1] = {1};
// Sample 2.
int * p_int1 = new int;
int * a_int1 = new int[1];
// Sample 3.
delete p_int1;
delete[] a_int1;
// Sample 4. If Sample 3 is an equivalent pair, then (given Sample 2)
// we can write
delete[] p_int1;
delete a_int1;
Granted, Sample 4 is bad practice.
I am thinking: "delete" will call the destructor of the object. delete[] will call the destructor for each element of the array, and then call the destructor for the array. new in Sample 2 would malloc (so to speak) the variable. new[] would malloc an array of one element, then malloc the one element. And then that one element would be set equal to 1. So, I'm thinking THAT'S why I need to call delete[] and not delete when I have an array of even one element. Am I understanding?
And if I am understanding, then calling delete instead of delete[] to free an array of one element, then I will certainly have a memory leak. A memory leak is the specific "bad thing" that will happen.
However, what about this:
int * a_int0 = new int[0];
delete a_int0;
Would THAT result in a memory leak?
I invite corrections of my misuse of terminology and anything else.
Sample 1:
int const * p_int = &one;
int a_int[1] = {1};
NO, these are not equivalent. A pointer is not the same thing as an array. They are not equivalent for the same reason that 1
is not the same as std::vector<int>{1}
: a range of one element is not the same thing as one element.
Sample 2:
int * p_int1 = new int;
int * a_int1 = new int[1];
These are sort of equivalent. You have to delete
them differently, but otherwise the way you would use p_int1
and a_int1
is the same. You could treat either as a range (ending at p_int1+1
and a_int1+1
, respectively).
Sample 3:
delete p_int1;
delete[] a_int1;
These are I suppose equivalent in the sense that both correctly deallocate the respective memory of the two variables.
Sample 4:
delete[] p_int1;
delete a_int1;
These are I suppose equivalent in the sense that both incorrectly deallocate the respective memory of the two variables.
int const * p_int = &one;
int a_int[1] = {1};
They are not equivalent, the first is a pointer to another variable, the other a mere array of size one, initialized straight away with the value one.
Understand this: pointers are entities in themselves, distinct from what they point to. Which is to say, the memory address of your p_int there, is entirely different from the memory address of your variable one. What's now stored in your p_int however, is the memory address of your variable one.
// Sample 2.
int * p_int1 = new int;
int * a_int1 = new int[1];
Here though, they are effectively the same thing in terms of memory allocation. In both cases you create a single int on the heap(new means heap space), and both pointers are immediately assigned the address of those heap allocated ints. The latter shouldn't be used in practice though, even though it's technically not doing anything outright wrong, it's confusing to read for humans as it conveys the notion that there is an array of objects, when there is in reality just one object, ie no arrayment has taken place.
// Sample 3.
delete p_int1;
delete[] a_int1;
Personally, I've never used the "array" delete, but yeah, what you're saying is the right idea: delete[] essentially means "call delete on every element in the array", while regular delete means "delete that one object the pointer points to".
// Sample 4. If Sample 3 is an equivalent pair, then (given Sample 2)
// we can write
delete[] p_int1;
delete a_int1;
Delete on array is undefined according to the standard, which means we don't really know what'll happen. Some compilers may be smart enough to see what you mean is a regular delete and vice versa, or they may not, in any case this is risky behavior, and as you say bad practice.
Edit: I missed your last point. In short, I don't know.
new int[0];
Basically means "allocate space for 0 objects of type int". That of course means 0 * 4, ie 0 bytes. As for memory leaks, what seems intuitive is no, as no memory has been allocated, so if the pointer goes out of scope, there is nothing on the heap anyway. I can't give a more in dept answer than that. My guess is that this is an example of undefined behavior, that doesn't have any consequences at all.
However, memory leaks happen when you do this:
void foo()
{
int* ptr = new int;
}
Notice how no delete is called as the function returns. The pointer ptr itself gets deallocated automatically, since it's located on the stack(IE automatic memory), while the int itself is not. Since heap memory isn't automatically deallocated, that tiny int will no longer be addressable, since you got no pointer to it anymore in your stack. Basically, those 4 bytes of heap memory will be marked as "in use" by the operating system, for as long as the process runs, so it won't be allocated a second time.
Edit2: I need to improve my reading comprehension, didn't notice you did delete the variable. Doesn't change much though: You never have memory leaks when you remember to delete, memory leaks arise when you forget to call delete on heap allocated objects(ie new
) prior to return from the scope the pointer to heap memory was located. My example is the simplest one I could think of.
This is a syntax-only answer. I checked this in a debugger with the following code:
// Equivalence Test 1.
*p_int = 2;
p_int[0] = 3;
*a_int = 2;
a_int[0] = 3;
Because I can access and manipulate the declarations as an array or as a pointer to variable, I think the declarations are syntactically equivalent, at least approximately.
I have to apologize
(1) I did not think to define my terms clearly. And it is very hard to talk about anything without my defining my terms. I should have realized and stated that I was thinking syntax and what a typical compiler would probably do. (2) I should have thought of checking in a debugger much earlier.
I think the previous answers are correct semantically. And of course good programming practice would declare an array when an array is the meaning, etc. for a pointer to variable.
I appreciate the attention that has been given to my question. And I hope you can be accepting of my slowness to figure out what I am trying to say and ask.
I figure that the other declarations can be checked out similarly in a debugger to see whether they are syntactically equivalent.
A Compiler's generating the same assembly would show syntactic equivalence. But if the assembly generated differs, then the assembly needs to be studied to see whether each does the same thing or not.