261
votes

A simple test app:

cout << new int[0] << endl;

outputs:

0x876c0b8

So it looks like it works. What does the standard say about this? Is it always legal to "allocate" empty block of memory?

6
+1 Very interesting question - although I'm not sure how much it matters in real code.Zifre
@Zifre: I'm asking for curiosity, but it might matter in real world, e.g. when size of allocated memory blocks is calculated in some way, and the result of the calculation might be zero, then there is no direct need to add exceptions to not allocate zero sized blocks.. Because they should be allocated and deleted without errors (if only the zero sized block is not dereferenced). So generally this gives wider abstraction of what a memory block is.anon
@emg-2: In your example situation, it actually wouldn't matter, because delete[] is perfectly legal on a NULL pointer :-).Evan Teran
It's only tangentially related - so I'm commenting here - but C++ in many ways ensures that distinct objects have unique addresses...even if they don't explicitly require storage. A related experiment would be to check the size of an empty struct. Or an array of that struct.Drew Dormann
To elaborate on Shmoopty's comment: Especially when programming with templates (e.g. policy class templates like std::allocator), it is common in C++ to have zero-sized objects. Generic code may need to dynamically allocate such objects and use pointers to them to compare object identity. This is why operator new() returns unique pointers for zero-sized requests. While arguably less important/common, the same reasoning applies to array allocation and operator new[]().Trevor Robinson

6 Answers

248
votes

From 5.3.4/7

When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.

From 3.7.3.1/2

The effect of dereferencing a pointer returned as a request for zero size is undefined.

Also

Even if the size of the space requested [by new] is zero, the request can fail.

That means you can do it, but you can not legally (in a well defined manner across all platforms) dereference the memory that you get - you can only pass it to array delete - and you should delete it.

Here is an interesting foot-note (i.e not a normative part of the standard, but included for expository purposes) attached to the sentence from 3.7.3.1/2

[32. The intent is to have operator new() implementable by calling malloc() or calloc(), so the rules are substantially the same. C++ differs from C in requiring a zero request to return a non-null pointer.]

24
votes

Yes, it is legal to allocate a zero-sized array like this. But you must also delete it.

15
votes

What does the standard say about this? Is it always legal to "allocate" empty block of memory?

Every object has a unique identity, i.e. a unique address, which implies a non-zero length (the actual amount of memory will be silently increased, if you ask for zero bytes).

If you allocated more than one of these objects then you'd find they have different addresses.

14
votes

Yes it is completely legal to allocate a 0 sized block with new. You simply can't do anything useful with it since there is no valid data for you to access. int[0] = 5; is illegal.

However, I believe that the standard allows for things like malloc(0) to return NULL.

You will still need to delete [] whatever pointer you get back from the allocation as well.

2
votes

Curiously, C++ requires that operator new return a legitimate pointer even when zero bytes are requested. (Requiring this odd-sounding behavior simplifies things elsewhere in the language.)

I found Effective C++ Third Edition said like this in "Item 51: Adhere to convention when writing new and delete".

2
votes

I guarantee you that new int[0] costs you extra space since I have tested it.

For example, the memory usage of

int **arr = new int*[1000000000];

is significantly smaller than

int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
    arr[i]=new int[0];
}

The memory usage of the second code snippet minus that of the first code snippet is the memory used for the numerous new int[0].