Maybe using std::vector
with a fixed maximal size?
If boost is allowed then boost::container::static_vector
and boost::container::small_vector
are the closest I can think of
boost::container::static_vector<int, 1024> my_array;
boost::container::small_vector<int, 1024> my_vector;
static_vector
is a sequence container like boost::container::vector
with contiguous storage that can change in size, along with the static allocation, low overhead, and fixed capacity of boost::array
.
The size of each object is still fixed but it can be worth it if the number of allocations is significant and/or the item count is small
If the vector can grow beyond the limit then just use boost::container::small_vector
. The heap is only touched when the size is larger than the defined limit
small_vector
is a vector-like container optimized for the case when it contains few elements. It contains some preallocated elements in-place, which can avoid the use of dynamic storage allocation when the actual number of elements is below that preallocated threshold.
If you use Qt then QVarLengthArray
is another way to go:
QVarLengthArray
is an attempt to work around this gap in the C++ language. It allocates a certain number of elements on the stack, and if you resize the array to a larger size, it automatically uses the heap instead. Stack allocation has the advantage that it is much faster than heap allocation.
Example:
int myfunc(int n)
{
QVarLengthArray<int, 1024> array(n + 1);
...
return array[n];
}
Some other similar solutions:
If a 3rd party solution isn't allowed then you can roll your own solution by wrapping std::array
in a struct to get a static vector
template<typename T, size_t N>
struct my_static_vector
{
explicit static_vector(size_t size) { } // ...
size_t size() const noexcept { return curr_size; }
static size_t capacity() const noexcept { return N; }
T& operator[](size_t pos) { return data[pos]; }
void push_back(const T& value) { data[curr_size++] = value; }
// ...
private:
std::array<typename T, N> data;
std::size_t curr_size;
}
And if small_vector
is required then you can use std::variant
to contain both the my_static_vector
and the vector
template<typename T, size_t N>
struct my_small_vector
{
explicit small_vector(size_t size) { } // ...
size_t size() const noexcept {
if (data.index() == 0) {
return data.get<0>().size();
} else {
return data.get<1>().size();
}
}
static size_t capacity() const noexcept {
if (data.index() == 0) {
return data.get<0>().capacity();
} else {
return data.get<1>().capacity();
}
}
// ...
private:
std::variant<my_static_vector<T, N>, std::vector<T>> data;
}
std::array
, the size of the array is a template parameter, so it cannot be a runtime variable. I guessstd::vector
is your best bet. – Astartestd::vector
with a custom allocator. Since you expect the data to be located "on the stack", presumably they will always be freed in reverse order they're allocated. It should be quite easy to write an extremely fast thread-local allocator given that restriction. The downside is that you will make a separate allocation up front to store the data, but this isn't all that different from what the OS does for your thread's stack - on a modern OS your block is virtual-only until used, just like the stack. But it won't benefit from the stack being hot in cache. – Lossaalloca
doesn't work too nicely with stateful objects and this is tagged C++. – Moriah