Dealing with your second question first:
If present, the std::size_t size argument must equal the size argument passed to the allocation function that returned ptr.
So, any extra space that might be allocated is the responsibility of the runtime library, not the client code.
The first question is more difficult to answer well. The primary idea is (or at least seems to be) that the size of a block often isn't stored right next to the block itself. In most cases, the size of the block is written, and never written again until the block is deallocated. To avoid that data polluting the cache while the block is in use, it can be kept separately. Then when you go to deallocate the block, the size will frequently have been paged out to disk, so reading it back in is quite slow.
It's also fairly common to avoid explicitly storing the size of every block explicitly at all. An allocator will frequently have separate pools for different sizes of blocks (e.g., powers of 2 from 16 or so up to around a couple kilobytes or so). It'll allocate a (fairly) large block from the OS for each pool, then allocate pieces of that large block to the user. When you pass back an address, it basically searches for that address through the different sizes of pools to find which pool it came from. If you have a lot of pools and a lot of blocks in each pool, that can be relatively slow.
The idea here is to avoid both of those possibilities. In a typical case, your allocations/deallocations are more or less tied to the stack anyway, and when they are the size you're allocating will likely be in a local variable. When you deallocate, you'll typically be at (or at least close to) the same level of the stack as where you did the allocation, so that same local variable will be easily available, and probably won't be paged out to disk (or anything like that) because other variables stored nearby are in use as well. For the non-array form, the call to ::operator new
will typically stem from a new expression
, and the call to ::operator delete
from the matching delete expression
. In this case, the code generated to construct/destroy the object "knows" the size it's going to request (and destroy) based solely on the type of object being created/destroyed.
operator new[]
to allocate that memory). – Ananiasoperator new[]
? Is it simplysizeof arr
? – Aldereteoperator new[]
. There is no way to fetch it if you didn't save it. – Balboaoperator delete[]
manually in the first place? – Ananiassize
from theoperator new
in my variable, which I then make sure I pass tooperator delete
. – Alderetenew/delete
expression, or even manually), and I was wondering why were they defined with a sized version. – Alderetestd::array
. It saves the size when you create the array, and can easily pass it when it callsdelete
on its members in its destructor. – Peggiepeggiroperator delete[]
should be? The compiler emits the call; it's its problem, not yours. (The compiler, obviously, knows how much storagenew T[N]
would request.) – Ananiasoperator new
. – Alderete