14

My question are located in my code comment:

int* a = new int[0];// I've expected the nullptr according to my logic...
bool is_nullptr = !a; // I got 'false'
delete[] a; // Will I get the memory leaks, if I comment this row?

Thank you.

banarun
  • 2,305
  • 2
  • 23
  • 40
Andrey Bushman
  • 11,712
  • 17
  • 87
  • 182
  • Why would you ever allocate `0` bytes? – Kolyunya Jul 02 '13 at 07:22
  • 3
    @Kolyunya Normally no one would, but what if the size is a variable that can be zero? – Some programmer dude Jul 02 '13 at 07:25
  • @JoachimPileborg could you please elaborate your point? I cant get it yet. The question is quite interesting for me. If we call `malloc(0)` shall we call `free` after? Is any memory allocated? – Kolyunya Jul 02 '13 at 07:30
  • 1
    Also the practical side of the question is interesting too. Are there any practical uses of allocating 0 bytes? Or it is just a conceptual question? – Kolyunya Jul 02 '13 at 07:33
  • 4
    Yes, if you call malloc(0), you will get back a valid pointer (that you obviously shouldn't try to write to). And you do need to "free" it. Same holds true for new/delete. – selbie Jul 02 '13 at 07:33
  • @Kolyunya - sometimes it makes sense to do this such as streamlining a code path without having to add extra logic to handle an "empty array" case. – selbie Jul 02 '13 at 07:35
  • @selbie so `malloc(0)` will result in some (non-zero) memory allocation? Why would it allocate anything? I can't get it. – Kolyunya Jul 02 '13 at 07:35
  • @selbie I mean if we requested `0` bytes, why would `malloc` allocate more? – Kolyunya Jul 02 '13 at 07:39
  • 1
    @selbie Calling `malloc(0)` may return a valid pointer that can be passed to `free`, or it may return `NULL`. It's implementation defined. – Some programmer dude Jul 02 '13 at 07:40
  • 1
    @Kolyunya I mean what if you have the size in a variable, that is coming from somewhere (file, user, database, etc.) and you use that variable for the allocation. If you don't have to add a special case for zero size, the code will most likely be much easier to write. – Some programmer dude Jul 02 '13 at 07:42
  • @JoachimPileborg now I get it. But it's probably good idea to have a special case for `0` value since `new int[0]` is an UB on C++03. – Kolyunya Jul 02 '13 at 07:45
  • Related to the discussion in the comments if not directly to the question: [What happens if I re-alloc and the new size is 0. Is this equivalent with a free?](http://stackoverflow.com/questions/2546572/) – dmckee --- ex-moderator kitten Jul 02 '13 at 16:05

5 Answers5

16

For C++11, and given your code:

int* a = new int[0];

Zero is a legal size, as per 5.3.4/7:

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

The operator invoked is as per 18.6.1.2 (emphasis mine):

void* operator new[](std::size_t size);

...

3 Required behavior: Same as for operator new(std::size_t). This requirement is binding on a replacement version of this function.

4 Default behavior: Returns operator new(size).

...referencing 18.6.1.1...

void* operator new(std::size_t size);

3 Required behavior: Return a non-null pointer to suitably aligned storage (3.7.4), or else throw a bad_- alloc exception. This requirement is binding on a replacement version of this function.

So, the pointer returned must be non-null.

You do need to delete[] it afterwards.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • Bjarne Stroustrup has answered to me: operator new always return a pointer to an object (it throws bad_alloc in case of memory exhaustion). If you don't use delete for a new, you get a leak. The exact amount of memory leaked is implementation specific, probably two or three words. – Andrey Bushman Jul 02 '13 at 13:10
  • 4
    @Bush: well, honestly I feel a bit sad that you took his time with something you'd already been told, but there you have it.... – Tony Delroy Jul 02 '13 at 13:26
  • 1
    No I got the answer by B. Stroustrup after your answer was marked as "answer". – Andrey Bushman Jul 02 '13 at 13:42
10

In C++03 new int[0] results in undefined behavior because the value between the [] must be a strictly positive value - zero is no good (5.3.4/6 "New"). So asking whether there's a memory leak afterwards is in a sense pointless.

In C++11 new int[0] results in a call to the allocator to allocate a zero length array (5.3.4/7 "New"). If the allocation request succeeds, a pointer is returned - there's nothing in the standard that says how much memory the block pointed to by that pointer contains, other than it has to be at least the requested size. However, it has at least the effect of allocating at least one character, because that address cannot be returned by the allocator again until it has been freed. In practice, the bookkeeping overhead will be more than one character.

David G
  • 94,763
  • 41
  • 167
  • 253
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 1
    Oh; I didn't know about this difference between C++03 and C++11; very interesting. C++03 does include the language "the _new-expression_ yields a pointer to the initial element **(if any)** of the array" (emphasis mine). When reading this in C++11, I assumed this text was to handle the case where the count is zero, but since it's present in C++03, perhaps it is also to handle the case where a non-throwing form returns null? – James McNellis Jul 02 '13 at 07:38
  • 4
    The comment about C++03 is totally incorrect. In C++03 (§5.3.4/6): "The expression in a direct-new-declarator shall have integral or enumeration type (3.9.1) with a non-negative value." 0 is a non-negative value. (There are, in fact, no changes here since C++98.) – James Kanze Jul 02 '13 at 08:36
  • 1
    "Every *constant-expression* ... shall ... evaluate to a strictly positive value" (emphasis by the Standard) - this talks about code like `new float[n][5]` (example taken from the Standard), where `5` (*constant-expression*) should be positive (and evaluated at compile time), and `n` (*expression*) should be non-negative (and evaluated at run time) – anatolyg Jul 02 '13 at 12:45
7

Yes, there is a leak, and it is not implementation-dependent.

This new expression cannot yield a null pointer. It allocates memory by calling operator new[], which is required to "return a non-null pointer to suitably aligned storage, or else throw a bad_alloc exception" (see C++11 §18.6.1.1/3 and §18.6.1.2/3).

Further, the allocation function requirements (§3.7.4.1) require that each call to an allocation function returns a pointer that is distinct from all other pointers that have been allocated but not yet deallocated. Thus, the implementation cannot simply have a single "empty allocation" pointer that it always returns.

This, every array-form new expression allocates something, even if the extent is zero. If you don't deallocate that object via delete[], you have leaked it.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
4

Yes, without delete there will be a memory leak.

Every new has to be paired with delete. Even if the programmer-allocated size is 0. Allocator may allocate more memory than requested because of alignment requirements, management overhead or anything else.

Juraj Blaho
  • 13,301
  • 7
  • 50
  • 96
  • How will it be a memory leak? How much memory will leak? – Kolyunya Jul 02 '13 at 07:20
  • 3
    @Kolyunya I would imagine that is up to the memory allocator. – David Brown Jul 02 '13 at 07:22
  • Also, the allocator must return a new pointer for each `new int[0]` request, and these pointers must be unique across all allocations. It is evident that after some number of `new` not followed by `delete`, one will run out of pointers – user4815162342 Jul 02 '13 at 07:29
4

In this case it is implementation defined whether you will be returned a nullptr or not but you should be careful that you do not dereference this pointer also not calling delete will result in a Memory leak.

W.r.t to calling delete the rule is simple:
"If you call new you must call delete."

Correction:
As the citations in other answers have made clear, It cannot return you a nullptr.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • What will happen if you don't call `delete` in the example? How much memory will leak? – Kolyunya Jul 02 '13 at 07:21
  • 1
    @Kolyunya: If you don't call `delete` whatever memory was allocated(*depends on implementation*) will be leaked. Only thing thats sure is that It will be non-zero. – Alok Save Jul 02 '13 at 07:23
  • I used to think if you allocate `0` bytes there is nothing to delete... Thank you for an information. – Kolyunya Jul 02 '13 at 07:25
  • 2
    It is not implementation-dependent. `new T[0]` cannot yield `nullptr`. – James McNellis Jul 02 '13 at 07:32
  • 1
    @Kolyunya The memory allocator usually has to allocate extra book-keeping structures to store your heap blocks, so even a 0-byte block will have a bit of overhead. Usually that overhead is around 8-16 bytes per heap block, but it can vary (and is implementation-dependent). – Thomas Jul 02 '13 at 12:28