C++17stladvanced
std::pmr::memory_resource
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
An abstract base class defining the interface for custom memory allocators. It provides `allocate()`, `deallocate()`, and `is_equal()` virtual functions, decoupling allocation strategy from container types and enabling runtime-configurable allocators.
Real-World Scenario
Define a logging allocator that tracks every allocation for debugging memory usage in a server application.
Quick Snippet
snippet.cpp
#include <memory_resource>
class LoggingResource : public std::pmr::memory_resource {
void* do_allocate(size_t bytes, size_t align) override {
std::cout << "Allocating " << bytes << " bytes\n";
return std::pmr::get_default_resource()->allocate(bytes, align);
}
void do_deallocate(void* p, size_t bytes, size_t align) override {
std::pmr::get_default_resource()->deallocate(p, bytes, align);
}
bool do_is_equal(const memory_resource& other) const noexcept override {
return this == &other;
}
};Full Example
memory_resource.cpp
// CodeNebula - C++17 Example: std::pmr::memory_resource
// Compile: g++ -std=c++17 -Wall -Wextra -o example memory_resource.cpp
// Demonstrates std::pmr::memory_resource, the abstract base class for
// polymorphic allocators. Shows how to implement a custom memory resource,
// use the default/null resources, and swap resources at runtime.
#include <iostream>
#include <memory_resource>
#include <vector>
#include <cstdlib>
// ------------------------------------------------------------------
// Custom memory resource that logs allocations
// ------------------------------------------------------------------
class LoggingResource : public std::pmr::memory_resource {
std::string name_;
std::pmr::memory_resource* upstream_;
public:
explicit LoggingResource(std::string name,
std::pmr::memory_resource* up = std::pmr::get_default_resource())
: name_(std::move(name)), upstream_(up) {}
protected:
void* do_allocate(std::size_t bytes, std::size_t alignment) override {
std::cout << " [" << name_ << "] allocate(" << bytes
<< ", align=" << alignment << ")" << std::endl;
return upstream_->allocate(bytes, alignment);
}
void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override {
std::cout << " [" << name_ << "] deallocate(" << bytes << ")" << std::endl;
upstream_->deallocate(p, bytes, alignment);
}
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
return this == &other;
}
};
int main()
{
// ------------------------------------------------------------------
// 1. Default and null memory resources
// ------------------------------------------------------------------
std::cout << "=== Built-in Resources ===" << std::endl;
auto* def = std::pmr::get_default_resource();
auto* null_res = std::pmr::null_memory_resource();
std::cout << " default resource : " << def << std::endl;
std::cout << " null resource : " << null_res << std::endl;
std::cout << " Are they equal? : " << (*def == *null_res) << std::endl;
// ------------------------------------------------------------------
// 2. Custom logging resource
// ------------------------------------------------------------------
std::cout << "\n=== Custom Logging Resource ===" << std::endl;
LoggingResource logger("MyAlloc");
std::pmr::vector<int> vec(&logger);
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
std::cout << " vec contents: ";
for (int v : vec) std::cout << v << " ";
std::cout << std::endl;
// ------------------------------------------------------------------
// 3. null_memory_resource always throws on allocate
// ------------------------------------------------------------------
std::cout << "\n=== Null Resource ===" << std::endl;
try {
null_res->allocate(1);
} catch (const std::bad_alloc& e) {
std::cout << " null_memory_resource threw: " << e.what() << std::endl;
}
// ------------------------------------------------------------------
// 4. Setting a new default resource
// ------------------------------------------------------------------
std::cout << "\n=== Set Default Resource ===" << std::endl;
LoggingResource global_logger("Global");
std::pmr::memory_resource* old = std::pmr::set_default_resource(&global_logger);
// Now any pmr container using default resource will use our logger
std::pmr::vector<int> vec2; // Uses new default
vec2.push_back(42);
std::cout << " vec2[0] = " << vec2[0] << std::endl;
// Restore original default
std::pmr::set_default_resource(old);
std::cout << " Default resource restored" << std::endl;
return 0;
}
/*
Expected output (addresses vary):
=== Built-in Resources ===
default resource : 0x...
null resource : 0x...
Are they equal? : 0
=== Custom Logging Resource ===
[MyAlloc] allocate(4, align=4)
[MyAlloc] allocate(8, align=4)
[MyAlloc] deallocate(4)
[MyAlloc] allocate(16, align=4)
[MyAlloc] deallocate(8)
vec contents: 10 20 30
=== Null Resource ===
null_memory_resource threw: bad_alloc
=== Set Default Resource ===
[Global] allocate(4, align=4)
vec2[0] = 42
Default resource restored
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example memory_resource.cpp