7

When I allocate a dynamic array in C++ (T * p = new T[n]), I use delete [] p to free the allocated memory. Obviously, the system knows the array size (in order among other things to call n times T's destructor). This is discussed elsewhere. For instance How does delete[] “know” the size of the operand array?. This is implemenation details.

But why was it not decided to make this information available?

Thx

jww
  • 97,681
  • 90
  • 411
  • 885
asbxl
  • 123
  • 3
  • 1
    Because `std::vector`. Seriously, that's what it's trying to encourage you to use. – StoryTeller - Unslander Monica Jan 10 '18 at 14:03
  • 1
    You could have a look at Doug Mclean comment in this answer https://stackoverflow.com/a/197699/5076707 – Pumkko Jan 10 '18 at 14:06
  • so I have a declaration of new [] that always allocates 1024 items. no matter how many were passed - on attempting to get more, I throw a bad_alloc. The size just isn't available anymore. That's the implementation detail that breaks your example – UKMonkey Jan 10 '18 at 14:06
  • For example, if I make an app where I know that most of my objects are going to be alive up to the end of execution and I know that the maximum size of memory I'm going to need is going to be relatively small I can just pre-allocate a chunk of memory and pass out pointers in it with overloaded `new` and `new[]`, then do a no-op `operator delete` and `operator delete[]` because I know I won't need that memory again. I wouldn't need to store the size of each allocation, just a `next` pointer. – patatahooligan Jan 10 '18 at 14:10
  • @UKMonkey -- no; `operator new[]` doesn't allocate **items**; it allocates **space for items**. `new X[whatever]` doesn't care how much space was actually allocated, as long as it's at least the amount that the compiler requested in the call to `operator new[]`. The compiler generates code to keep track of the number of objects that were constructed, usually in "extra" memory at the beginning of the allocated block. – Pete Becker Jan 10 '18 at 14:50
  • @PeteBecker maybe I didn't describe it very well... my point was `The compiler generates code to keep track of the number of objects that were constructed` doesn't need to be true - it is as a rule of thumb, but it doesn't have to. In the case it doesn't, the size just isn't available. – UKMonkey Jan 10 '18 at 14:55

4 Answers4

4

delete[] might not necessarily know the exact array size. It might over-allocate for example, or do something else entirely bizarre yet conformant with the standard.

Facetiously the answer could also be on the lines that nobody has managed to convince the standards committee of the merits of the idea; perhaps sizeof[](p) could be the proposed syntax? sizeof is already a keyword, already has a runtime-evaluable flavour in C so it's not an enormous leap to envisage an equivalent in C++, and my [] distinguishes from sizeof(pointer type).

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 3
    +1. A concrete example `new char[7]` on almost all modern optimising heaps will go through a low fragmentation/bucketing heap in the 8 byte bucket and have no idea about its size if queried. Storing the size when no one (currently) needs to know isn't optimal. – Mike Vine Jan 10 '18 at 14:40
  • Is there any chance of `sizeof[](p)` conflicting with lambda syntax somehow? – Jesin Jan 10 '18 at 18:05
2

It would inhibit optimisations where knowledge of array size is not nessesary:

int* foo = new int[...];
. . .
delete[] foo;

As int is a trivial type and does not have a destructor, compiler do not need to know how many ints are there. Even if it is an array of 1 int in 4 MB memory chunk.

const MyType* const foo = new MyType[. . .];
. . .
delete[] foo;

Here compiler knows size of the array, pointed by foo, and it knows, that it cannot change legally. So it just can use that information directly, and do not store amount of items in allocated array.

Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48
0

Because new is not the only source for dynamic array (which share the same signature with pointer to objects), it has to be compatible with C.

Think about this:

void seem_good(MyStruct* d) {
  mess_with(d[3]);
}

The compiler have no way to perform check if it wanted to be called from other languages.


By the way, when inter-operation with other languages is not needed, C++ has its own solution: std::array.

Non-maskable Interrupt
  • 3,841
  • 1
  • 19
  • 26
  • 1
    But how does this answer why there can't be a function `sizeofallocation(void *p)` that might as well be UB for pointers that didn't come from `new` or `new[]`. Can you elaborate? – patatahooligan Jan 10 '18 at 14:14
  • A good spec should try to eliminate ambiguous keyword. `sizeofallocation(void *p)` is asking for trouble when programmer pass in ordinary pointers. Even you introduce new keyword that's paired with `new`/`delete` and UD for incompatible pointer, it only provide a feature that is already solved by `std::array`. – Non-maskable Interrupt Jan 10 '18 at 14:34
  • 1
    @Non-maskableInterrupt -- `delete [] p;` is also asking for trouble when the programmer passes a pointer that wasn't returned by `new[]`. The possibility that something could be misused is not a reason for not having it. – Pete Becker Jan 10 '18 at 14:52
  • The programmer needs to keep track of what pointers they've `new`ed anyway so I don't believe that's an issue here. And `std::array` doesn't solve run-time determined sizes. For the record, I don't think such a function should exist, I was just asking about your answer because I don't get it. – patatahooligan Jan 10 '18 at 14:53
0

It's implementation-specific. One possible way the runtime tracks the size is to store it in memory just before the returned pointer, but its not something you can count on. I was once tasked with tracking (heap) memory usage so I did exactly this - wrote a custom allocator that allocated some extra bytes, stored the size and returned an offset pointer. When you delete you need to "unoffset" the pointer, do what you need to with the size, then delete.

virgesmith
  • 762
  • 1
  • 7
  • 18