|
||||
|
Section 38:
|
[38.7] How do compilers use "over-allocation" to remember the number of elements in an allocated array?
Recall that when you delete[] an array, the runtime system magically knows how many destructors to run. This FAQ describes a technique used by some C++ compilers to do this (the other common technique is to use an associative array). If the compiler uses the "over-allocation" technique, the code for p = new Fred[n] looks something like the following. Note that WORDSIZE is an imaginary machine-dependent constant that is at least sizeof(size_t), possibly rounded up for any alignment constraints. On many machines, this constant will have a value of 4 or 8. It is not a real C++ identifier that will be defined for your compiler.
// Original code: Fred* p = new Fred[n];
char* tmp = (char*) operator new[] (WORDSIZE + n * sizeof(Fred));
Fred* p = (Fred*) (tmp + WORDSIZE);
*(size_t*)tmp = n;
size_t i;
try {
for (i = 0; i < n; ++i)
new(p + i) Fred(); // Placement new
}
catch (...) {
while (i-- != 0)
(p + i)->~Fred(); // Explicit call to the destructor
operator delete[] ((char*)p - WORDSIZE);
throw;
}
Then the delete[] p statement becomes:
// Original code: delete[] p; size_t n = * (size_t*) ((char*)p - WORDSIZE); while (n-- != 0) (p + n)->~Fred(); operator delete[] ((char*)p - WORDSIZE);Note that the address passed to operator delete[] is not the same as p. Compared to the associative array technique, this technique is faster, but more sensitive to the problem of programmers saying delete p rather than delete[] p. For example, if you make a programming error by saying delete p where you should have said delete[] p, the address that is passed to operator delete(void*) is not the address of any valid heap allocation. This will probably corrupt the heap. Bang! You're dead! |
|||