Home » Software development: Special allocators with C++17​

Software development: Special allocators with C++17​

by admin
Software development: Special allocators with C++17​

Software development: Special allocators with C++17​

In my last article “Software Development: Polymorphic Allocators with C++17” I introduced the theory of polymorphic allocators in C++17. Today I will apply the theory.

Advertisement

Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages ​​C++, Python and Haskell, but also enjoys speaking frequently at specialist conferences. On his blog Modern C++ he deals intensively with his passion C++.

Before I continue, here are the most important parts of my last article “Software Development: Polymorphic Allocators with C++17”.

The following program uses polymorphic allocators:

// polymorphicAllocator.cpp

#include
#include
#include
#include

int main() {

std::array<:byte> buf1; // (1)
std::pmr::monotonic_buffer_resource pool1{buf1.data(),
buf1.size()};
std::pmr::vector myVec1{&pool1}; // (3)
for (int i = 0; i myVec2{&pool2};
for (int i = 0; i Now I want to focus on myVec2. 200 ints are saved to the std::pmr::vector pushed. These 200 ints don’t fit in a char buf[200] and that’s why std::pmr::new_delete_resource() steps in as a so-called upstream allocator and calls the global new for the remaining elements. I will now instrumentalize the upstream allocator.

The following program is based on the previous one, uses a tracking allocator and makes dynamic memory allocation and deallocation visible.

// trackAllocator.cpp

#include
#include
#include #include
#include
#include

class TrackAllocator : public std::pmr::memory_resource {
void* do_allocate(std::size_t bytes,
std::size_t alignment) override {
void* p = std::pmr::new_delete_resource()->
allocate(bytes, alignment);
std::cout
deallocate(p, bytes, alignment);
}

bool do_is_equal(const std::pmr::memory_resource& other)
const noexcept override {
return std::pmr::new_delete_resource()->is_equal(other);
}
};

int main() {

std::cout buf1;
std::pmr::monotonic_buffer_resource pool1{buf1.data(),
buf1.size()};
std::pmr::vector myVec1{&pool1}; // (3)
for (int i = 0; i myVec2{&pool2}; // (4)
for (int i = 0; i TrackAllocator is an allocator for tracking memory allocation and its release. It derives from the interface class std::pmr::memory_resource, from which all memory resources derive. TrackAllocator defines the three required member functions do_allocate, do_deallocate and do_is_equal. Each call forwards this to the call to std::pmr::new_delete_resource. std:pmr::new_delete_resource is the default storage resource and calls the global new and delete. The job of the do_is_equal member function is to check whether the two memory resources are equal. The interesting point about the example is that I visualize the allocation and deallocation of memory in the do_allocate and do_deallocate member functions.

See also  Windows 11 gets a new look with AI: what the new Moment 4 update brings

The Concepts introduced with C++20, along with the Ranges library, modules and coroutines, have redefined how to build modern C++ applications. From the November 7th to 9th, 2023 Rainer Grimm brings you up to date in his intensive workshop C++20: the new concepts are comprehensively explained and goes into the many useful functions that C++20 brings with it.

I instantiate the TrackAllocator (line 1) and make it the default resource (2). myVec1 (3) and myVec2 (4) use it as an upstream allocator. This allocator steps in when the primary allocator is consumed. This fallback is not necessary for myVec1, but it is necessary for myVec2.

This output shows the dynamic allocation and release of myVec2, through std::pmr::vector can hold all ints.

An upstream allocator can also be tied to a specific container.

std::pmr::null_resource_allocator is a special allocator. Using them for allocation results in a std::bad_alloc exception. This memory resource ensures that memory is not randomly allocated on the heap:

// nullMemoryResource.cpp

#include
#include
#include
#include
#include
#include

int main() {

std::cout buf;
std::pmr::monotonic_buffer_resource pool{buf.data(),
buf.size(), // (1)
std::pmr::null_memory_resource()};
std::pmr::vector<:pmr::string> myVec{&pool}; // (2)
try {
for (int i = 0; i First I allocate memory on the stack and initialize std::pmr::monotonic_buffer_resource with it. Then I use this memory resource and std::pmr::null_memory_resource as upstream allocator (1). In (2) I create a std::pmr::vector<:pmr::string>. Since I’m using a std::pmr::string, the string also uses the memory resource and its upstream allocator. If I use std::pmr::vector<:string> std::string uses the global allocators new and delete. Finally, I create 100 strings in (3) and catch a std::bad_alloc exception in (4). I got what I deserved: 100 strings don’t fit in a std::array<:byte>-Buffer. After 17 strings the buffer is used up.

See also  The revolution in the fields goes from automation and machine learning

The std::pmr::monotonic_buffer has excellent properties. It’s pretty fast and doesn’t free up memory. My next article will provide the numbers. (rme)

To home page

You may also like

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More

Privacy & Cookies Policy