This tip will show you how to allocate variable-size arrays on the stack to be used with C++17 containers.
Introduction
C language provides the alloca
function to allocate arbitrary size array on the stack. After the function returns or the scope ends, the stack memory is automatically reclaimed back (popped back) without the developer having to deallocate it explicitly and thereafter is unsafe to access it again from another function. The below code shows allocating fixed size and arbitrary size stack memory. While arbitrary size stack memory has flexibility, care has to be taken that not too much is allocated to exhaust all the available stack memory (default is 1MB), especially if the developer is writing a library and has no control over how his library is used. For instance, his library may be used in a worker thread with only 10KB of stack memory.
int buf[10];
char* buf = (char*)alloca(10 * sizeof(int));
Starting from C++17, it is possible to specify a memory buffer to be used for containers in the std::pmr
namespace. PMR stands for Polymorphic Memory Resources. Though containers in std
and std::pmr
namespace have similar interface, they are not interchangeable. To use std::pmr
containers such as string
and vector
, C++17 has to be enabled first in the Visual C++ project properties. See screenshot below.
The std::pmr::string
example allocates a buffer with alloca
and passes it to monotonic_buffer_resource
which is then passed into the std::pmr::string
.
#include <iostream>
#include <string>
#include <memory_resource>
char* buf = (char*)alloca(200);
std::pmr::monotonic_buffer_resource pool{ buf, 200 };
std::pmr::string str{ &pool };
str = "just a non-SSO string";
std::cout << str << std::endl;
The std::pmr::vector
example allocates on the stack and construct monotonic_buffer_resource
, with that buffer. The std::pmr::vector
takes in the monotonic_buffer_resource
.
#include <iostream>
#include <vector>
#include <string>
#include <memory_resource>
char* buf = (char*)alloca(200000);
std::pmr::monotonic_buffer_resource pool{ buf, 200000 };
std::pmr::vector<std::string> coll{ &pool };
for (int i = 0; i < 1000; ++i) {
coll.emplace_back("just a non-SSO string");
}
What happens when the PMR container runs out of the assigned memory buffer? It shall allocate on the heap or the upstream memory resource specified at its constructor.
C# stackalloc
Interestingly, C# also has a similar feature such as the stackalloc keyword that allocates on the stack as opposed to the new
keyword which allocates on the heap through the Garbage Collector (GC).
int length = 3;
Span<int> numbers = stackalloc int[length];
for (var i = 0; i < length; i++)
{
numbers[i] = i;
}
Reference
History
- 25th May, 2020: Initial version