patterncppMinor
Fast variable-length stack allocator for vector<> in C++
Viewed 0 times
faststacklengthforallocatorvariablevector
Problem
I wrote a variable-length stack allocator for the
The purpose of this class is to improve performance of allocation of small arrays on the stack whose size cannot be determined at compile-time while still retaining the helpful features of the
```
#pragma once
#include
template
class stack_allocator {
template friend class stack_allocator;
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template
struct rebind {
typedef stack_allocator other;
};
private:
T* ptr;
size_t currentSize, maxSize;
public:
stack_allocator() noexcept :
ptr(nullptr),
currentSize(0),
maxSize(0) {
}
stack_allocator(T* buffer, size_t size) noexcept :
ptr(buffer),
currentSize(0),
maxSize(size) {
}
template
explicit stack_allocator(const stack_allocator& other) noexcept :
ptr(reinterpret_cast(other.ptr)),
currentSize(other.currentSize),
maxSize(other.maxSize) {
}
T allocate(size_t n, const void hint = nullptr) {
T* pointer = ptr + currentSize;
currentSize += n;
return pointer;
}
void deallocate(T* p, size_t n) {
currentSize -= n;
}
size_t capacity() const noexcept {
return maxSize;
}
size_t max_size() const noexcept {
return maxSize;
}
T* address(T& x) const noexcept {
return &x;
}
const T* address(const T& x) const noexcept {
return &x;
}
T* buffer() const noexcept {
return ptr;
}
template
st
vector<> class in C++ 11. In order to be able to allocate size dynamically at runtime I made use of the non-standard alloca() function, which is available in a multitude of C++ implementations, including GCC and Visual Studio.The purpose of this class is to improve performance of allocation of small arrays on the stack whose size cannot be determined at compile-time while still retaining the helpful features of the
vector<> class.```
#pragma once
#include
template
class stack_allocator {
template friend class stack_allocator;
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template
struct rebind {
typedef stack_allocator other;
};
private:
T* ptr;
size_t currentSize, maxSize;
public:
stack_allocator() noexcept :
ptr(nullptr),
currentSize(0),
maxSize(0) {
}
stack_allocator(T* buffer, size_t size) noexcept :
ptr(buffer),
currentSize(0),
maxSize(size) {
}
template
explicit stack_allocator(const stack_allocator& other) noexcept :
ptr(reinterpret_cast(other.ptr)),
currentSize(other.currentSize),
maxSize(other.maxSize) {
}
T allocate(size_t n, const void hint = nullptr) {
T* pointer = ptr + currentSize;
currentSize += n;
return pointer;
}
void deallocate(T* p, size_t n) {
currentSize -= n;
}
size_t capacity() const noexcept {
return maxSize;
}
size_t max_size() const noexcept {
return maxSize;
}
T* address(T& x) const noexcept {
return &x;
}
const T* address(const T& x) const noexcept {
return &x;
}
T* buffer() const noexcept {
return ptr;
}
template
st
Solution
Well this is going to cause problems:
You can't assume that the last allocated object is the one that is de-allocated (I would even say that will never happen).
As a result your next call to allocate is going to re-use that memory even though it is already being used.
Your allocator assumes that its memory is allocated with
Also relying on this kind of low level functions is dangerous. What happens when the vector is part of an object? What if the object that holds it is dynamically allocated? There are too many flaws in this design for it be used anywhere apart from your one small use case senario and even then it will need to be well documented to make sure that a future maintainer does not break it.
void deallocate(T* p, size_t n) {
currentSize -= n;
}You can't assume that the last allocated object is the one that is de-allocated (I would even say that will never happen).
As a result your next call to allocate is going to re-use that memory even though it is already being used.
T* allocate(size_t n, const void* hint = nullptr) {
T* pointer = ptr + currentSize;
currentSize += n;
return pointer;
}Your allocator assumes that its memory is allocated with
alloca(). But the interface allows any memory to be injected so it has a high likely hood that it is going to be used incorrectly and leak memory. If you are assuming that the memory is going to be free'ed dynamically like that then you need to design the allocator to allocate the appropriate memory.Also relying on this kind of low level functions is dangerous. What happens when the vector is part of an object? What if the object that holds it is dynamically allocated? There are too many flaws in this design for it be used anywhere apart from your one small use case senario and even then it will need to be well documented to make sure that a future maintainer does not break it.
Code Snippets
void deallocate(T* p, size_t n) {
currentSize -= n;
}T* allocate(size_t n, const void* hint = nullptr) {
T* pointer = ptr + currentSize;
currentSize += n;
return pointer;
}Context
StackExchange Code Review Q#155389, answer score: 6
Revisions (0)
No revisions yet.