C/C++: Allocate Variable-size Arrays on the Stack

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 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.

// allocate fixed-length memory on the stack:
int buf[10];

// allocate arbitrary-length memory on the stack:
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.

enable_cpp17

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>

// allocate some memory on the stack:
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>

// allocate some memory on the stack:
char* buf = (char*)alloca(200000);

// and use it as initial memory pool for a vector:
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 allocate 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

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close