A modern C++17 header-only, cross-platform shared memory library.
- Header-only: No compilation required, just include and use
- Cross-platform: Works on Windows, Linux, and macOS
- Modern C++17: Uses modern C++ features and idioms
- RAII: Automatic resource management
- Hybrid error handling: Both exception and no-throw variants
- Type-safe: Clean, type-safe API
- Creator tracking: Know if you created or opened existing shared memory via
is_creator() - Well-tested: Comprehensive test suite with Catch2
- Well-documented: Extensive API documentation and examples
| Platform | Implementation | Status |
|---|---|---|
| Windows | CreateFileMapping / MapViewOfFile |
Supported |
| Linux | POSIX shm_open / mmap |
Supported |
| macOS | POSIX shm_open / mmap |
Supported |
Install with vcpkg:
# Install from vcpkg
vcpkg install slick-shm
# Or add to vcpkg.json manifest
{
"dependencies": ["slick-shm"]
}Then in your CMakeLists.txt:
find_package(slick-shm CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE slick::shm)Copy the include/slick directory into your project and include the header:
#include <slick/shm/shared_memory.hpp>include(FetchContent)
# Skip slick-shm's tests, examples, and install target
set(SLICK_SHM_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(SLICK_SHM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(SLICK_SHM_INSTALL OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
slick-shm
GIT_REPOSITORY https://github.com/SlickQuant/slick-shm.git
GIT_TAG v0.1.0 # See https://github.com/SlickQuant/slick-shm/releases for latest version
)
FetchContent_MakeAvailable(slick-shm)
target_link_libraries(your_target PRIVATE slick::shm)# Option 1: Add as subdirectory
add_subdirectory(path/to/slick-shm)
target_link_libraries(your_target PRIVATE slick::shm)
# Option 2: Install and find_package
find_package(slick-shm REQUIRED)
target_link_libraries(your_target PRIVATE slick::shm)#include <slick/shm/shared_memory.hpp>
#include <cstring>
int main() {
using namespace slick::shm;
// Create shared memory
shared_memory shm("my_shm", 1024, create_only);
// Write data
const char* message = "Hello, World!";
std::memcpy(shm.data(), message, std::strlen(message) + 1);
return 0;
}#include <slick/shm/shared_memory.hpp>
#include <iostream>
int main() {
using namespace slick::shm;
// Open existing shared memory
shared_memory shm("my_shm", open_existing, access_mode::read_only);
// Read data
const char* message = static_cast<const char*>(shm.data());
std::cout << message << std::endl;
// Remove the segment (required on POSIX, a no-op on Windows)
shared_memory::remove("my_shm");
return 0;
}- C++17 compatible compiler
- GCC 7+ or Clang 5+ (Linux/macOS)
- MSVC 2017+ or MinGW (Windows)
- CMake 3.14+ (only for building the examples and tests)
# Clone the repository
git clone https://github.com/SlickQuant/slick-shm.git
cd slick-shm
# Create build directory
mkdir build && cd build
# Configure
cmake ..
# Build
cmake --build .
# Run tests
ctest --output-on-failure
# Install (optional)
cmake --install . --prefix /usr/localSLICK_SHM_BUILD_EXAMPLES(default: ON): build the example programsSLICK_SHM_BUILD_TESTS(default: ON): build the unit testsSLICK_SHM_INSTALL(default: ON): generate the install target
- API reference: the full API
- Platform notes: how behavior and limits differ by platform
- Examples: longer examples and usage patterns
Owns a mapped segment. The destructor unmaps and closes it.
// Create new shared memory
shared_memory shm("name", 1024, create_only);
// Open existing shared memory
shared_memory shm("name", open_existing);
// Create or open
shared_memory shm("name", 1024, open_or_create);
// Access data
void* ptr = shm.data();
size_t size = shm.size();
// Check validity
if (shm.is_valid()) { /* ... */ }
// Static utilities
shared_memory::remove("name");
bool exists = shared_memory::exists("name");A non-owning view of a mapped segment.
shared_memory shm("name", 1024, create_only);
shared_memory_view view(shm); // Cheap to copyCopying a view never allocates. It holds only data, size, mode, and a borrowed
name pointer, so it's cheap to pass by value into worker threads or hot paths.
The name() pointer belongs to the shared_memory object (or caller-provided buffer)
the view was built from, so that source must outlive the view.
You can still move the source. shared_memory keeps its name in address-stable
storage, so a view stays valid when its source is moved or move-assigned, even
when a std::vector<shared_memory> reallocates. Building a view from a temporary
won't compile.
try {
shared_memory shm("test", 1024, create_only);
} catch (const shared_memory_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
if (e.code() == errc::already_exists) {
// Handle specific error
}
}shared_memory shm("test", 1024, create_only,
access_mode::read_write, std::nothrow);
if (!shm.is_valid()) {
std::cerr << "Error: " << shm.last_error().message() << std::endl;
}The examples directory has three programs:
- basic_writer.cpp creates a segment and writes a message to it
- basic_reader.cpp opens that segment and prints the message
- advanced_sync.cpp runs a writer thread and a reader thread that coordinate through
std::atomic
Build and run:
cd build
./examples/basic_writer # In one terminal
./examples/basic_reader # In another terminalThe tests use Catch2:
cd build
ctest --output-on-failureThey cover:
- Create/open operations
- Error handling (exceptions and no-throw)
- Move semantics
- Cross-process communication
- Platform-specific behavior
- Backed by the system paging file
- Names are used as-is. You can prefix them with
Global\,Local\, orSession\<id>\ - The kernel frees the segment when the last handle closes
- Uses
shm_open()/mmap(), backed by tmpfs on Linux - The library adds the leading
/for you - You must call
shared_memory::remove()to delete a segment. Closing every handle doesn't - Name length limits:
- macOS: 31 characters, counting the
/prefix - Linux: 255 characters
- For portable code, keep names to 30 characters or fewer
- macOS: 31 characters, counting the
See platform_notes.md for the details.
- Keep names short (30 characters or fewer) and alphanumeric so they work everywhere.
- Call
remove()when you're done. Windows doesn't need it, but POSIX does. - Synchronize access to the data with
std::atomicor your own locking. - Check for errors, either by catching exceptions or by calling
is_valid(). - Pass
shared_memory_viewto code that uses the memory but shouldn't own it. - Trust
size(), not your request. Withopen_or_createoropen_alwaysan existing segment may keep its own size, sosize()can be smaller than what you asked for. Usecreate_onlywhen the size must be exact. See Sizing an existing segment.
MIT. See LICENSE.
Issues and pull requests are welcome.
Slick Quant
- Inspired by Boost.Interprocess
- Tested with Catch2