stable_reference_buffer
Overview
stable_reference_buffer
manages dynamic memory with a stable, cross-shared-library reference count. Traditional std::shared_ptr
can fail when different shared libraries create their own copies of the reference count. By contrast, stable_reference_buffer
places the reference count in a consistently accessible location (an interprocess map), ensuring correct usage counts across multiple libraries within the same process.
Main Goal
Prevent accidental double-deletion or mismatched reference counts when a memory buffer is passed around among different shared libraries.
Key Features
- Cross-Library Safe: A single, unified reference count for each memory block, even if the block is shared across library boundaries.
- Stable Buffer Lifecycle: Each stable_reference_buffer
instance increments the shared ref-count; resetting or destructing decrements it. Deallocation occurs only when the last reference is gone.
- Delay Deallocation: A specialized scope guard delay_deallocation
can prevent memory from being freed while a library or plugin is still actively referencing the buffer.
Typical Usage
1. Allocate and Share Memory
#include <cbeam/container/stable_reference_buffer.hpp>
int main() {
// Allocate a buffer that can store 10 integers
cbeam::container::stable_reference_buffer buf(10, sizeof(int));
// 'get()' returns a raw pointer for direct access
auto* data = static_cast<int*>(buf.get());
for (int i = 0; i < 10; ++i) {
data[i] = i;
}
// Now pass 'buf' to another library or function.
// The reference count is tracked so deallocation won't happen prematurely.
return 0;
}
Here, buf
is “known,” meaning the system has a global reference count for the memory block. Another library receiving buf
can copy it or store it, and the usage count remains consistent.
2. Copy and Reference Counting
// Suppose we have an existing stable_reference_buffer `buf`
cbeam::container::stable_reference_buffer copy(buf);
// Both now refer to the same underlying memory
assert(copy.get() == buf.get());
assert(copy.use_count() == 2);
When copy
is destroyed or reset, the reference count decrements. The memory remains valid if another reference is still active.
3. Append Data
int additional[3] = {42, 43, 44};
buf.append(additional, sizeof(additional));
// The buffer grows, incorporating new content.
append
supports dynamic resizing. If the memory location changes, stable_reference_buffer
updates the global reference-tracking structures accordingly.
4. Delay Deallocation
{
cbeam::container::stable_reference_buffer::delay_deallocation guard;
// Within this scope, memory blocks created or copied won't be freed
// even if their ref-count reaches zero, until after we exit the scope.
cbeam::container::stable_reference_buffer temp(10, sizeof(int));
// ... do work ...
temp.reset(); // Normally frees memory if no references remain,
// but 'delay_deallocation' defers it until scope exit.
}
// Exiting the scope now potentially frees memory whose ref-count was zeroed.
This is especially helpful if a plugin (which allocated the buffer) is about to unload but another library is still referencing the raw pointer. Keeping the memory alive until the end of delay_deallocation
scope prevents crashes or undefined behavior.
Motivation
When multiple shared libraries each see a memory block with a shared pointer, they may use different static runtime data, resulting in mismatched reference counts and double-frees. By using a stable, process-wide map for reference counts, stable_reference_buffer
solves:
- Potential Double-Free: Eliminates the risk that each library tries to free the block.
- Consistent Lifecycle: Ensures all references remain valid as long as at least one library holds the buffer.
When to Use
- Inter-Library Data Sharing: If you pass dynamic memory across library boundaries,
stable_reference_buffer
ensures a single reference count. - Delayed Destruction: If you’re unsure when a library might unload, use
delay_deallocation
to ensure memory remains accessible. - Complex Systems: Plugin architectures or multi-DLL setups benefit greatly from robust, stable memory references.