简体   繁体   中英

why does std::allocator::deallocate require a size?

std::allocator is an abstraction over the underlying memory model, which wraps the functionality of calling new and delete . delete doesn't need a size though, but deallocate() requires it.

void deallocate( T* p, std::size_t n );
"The argument n must be equal to the first argument of the call to allocate() that originally produced p; otherwise, the behavior is undefined."

Why?

Now I either have to make additional calculations before deallocating, or start storing the sizes that I passed to allocate. If I didn't use the allocator I wouldn't have to do this.

The design of the std::allocator API - the Allocator concept - is to facilitate the job of potential replacements.

std::allocator is an abstraction over the underlying memory model

It doesn't have to be! In general, an allocator does not need to use C malloc and free , nor delete or the not-in-place new . Yes, the default one usually does it, but the allocator mechanism isn't merely an abstraction over C's memory model. To be different is often the whole purpose of a custom allocator. Remember that allocators are replaceable: a particular std::allocator might not need the size for deallocation, but any replacements are likely to.

A compliant implementation of std::allocator is free to assert that you indeed pass the correct n to deallocate , and to otherwise depend on the size being correct.

It happens that malloc and free store the chunk size in its data structures. But in general an allocator might not do it, and requiring it to do so is premature pessimization. Suppose you had a custom pool allocator and were allocating chunks of int s. On a typical 64-bit system it'd be a 200% overhead to store a 64-bit size_t along with the 32-bit int . The user of the allocator is much better positioned to either store the size along in the allocation, or to determine the size in a cheaper fashion.

Good malloc implementations don't store allocation size for every small allocation; they and are able to derive the chunk size from the pointer itself eg by deriving a block pointer from the chunk pointer, and then inspecting the block header for the chunk size. That's but a detail of course. You could obtain the lower bound on the size using platform-specific APIs, such as malloc_size on OS X, _msize on Windows, malloc_usable_size on Linux.

It is often useful for memory-allocation algorithms to minimize the amount of overhead they require. Some algorithms which keep track of free areas rather than allocated areas can reduce the total amount of overhead to a low constant value with zero per-block overhead (book-keeping information is stored entirely within the free areas). On systems using such algorithms, an allocation request removes storage from the free pool, and a de-allocation request adds storage to the free pool.

If allocation requests for 256 and 768 bytes get satisfied using a contiguous region of the pool, the memory-manager state would be identical to what it would be if two requests for 512 bytes had been satisfied using that same region. If the memory manager were passed a pointer to the first block and asked to release it, it would have no way of knowing whether the first request had been for 256 bytes, or 512 bytes, or any other number, and thus no way of knowing how much memory should be added back to the pool.

Implementing "malloc" and "free" on such a system would require that it store the length of each block at the beginning of its region of storage and return a pointer to the next suitably-aligned address that would be available after that length. It's certainly possible for an implementation to do that, but it would add 4-8 bytes of overhead to each allocation. If the caller can tell the deallocation routine how much storage to add back to the memory pool, such overhead can be eliminated.

Furthermore, it is quite easy to accommodate this design point: simply allocate things as a struct , and store the size as an element within that struct . Your code that calls the deallocator now knows what value to provide, since the structure itself contains it.

By doing this, you're essentially doing exactly what any other language-implementation might be graciously doing for you. You're just doing the same thing explicitly.

Now, given that we're talking about C++ , which has oodles of great container-classes already built in, I would candidly encourage you to avoid "rolling your own" if you can possibly avoid it. Just find a way to use one of the nifty container-classes that the language and the standard library already provide.

Otherwise, be sure to package what you're building here as a home-grown container class. Be sure that the logic which deals with the allocator and the deallocator occurs only once in your program. (Namely, within this class.) Sprinkle it generously with logic that is specifically designed to detect bugs. (For instance, a sentinel value that is inserted into an object when it is allocated, and that must be found when the object is deallocated, and which is wiped-out just before it is. Explicit checks of the stored size-value to make sure that it makes sense. And so on.)

You're not required to keep track of the size. The standard allocator does not keep track of the size because it assumes a size for all allocations. Of course, there are different types of allocators for different purposes. A block size allocator, as you may have guessed, has a fixed size. Some applications like video games pre-allocate memory all upfront and eliminate the overhead of needing to keep track of the size for each allocation.

The standard library tries to be as generic as possible. Some allocators need to keep track of the size, others do not, but all allocators are required to conform to the interface.

我没有确凿的证据,但是我的直觉是不需要使用C ++运算符new / delete分配器,并且不妨使用不具有分配数组和了解其大小的能力的内存管理例程-例如malloc,例如。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM