owner_atomic_shared_ptr is a smart pointer implementation that solves the circular reference memory leak problem inherent in traditional std::shared_ptr. Inspired by Nim's ORC (Owner & Reference Counting) mechanism.
The main idea behind this implementation is that each heap object has exactly one owner and a set of references:
- Owner: The primary smart pointer responsible for the object's lifetime (typically a stack-allocated pointer)
- References: Other smart pointers that reference the same object but don't own it
When the owner is destroyed, ownership is transferred to the first reference in the set, creating a chain of ownership that eventually leads to memory deallocation - even with circular references!
Release Logic:
┌──────────────────────────────────────┐
│ Is this pointer the owner? │
│ │ │
│ ┌────┴────┐ │
│ YES NO │
│ │ │ │
│ │ ├──► Remove from ref_set
│ │ │ (just decrease reference count)
│ │ │
│ ▼ │
│ Are there any references? │
│ │ │
│ ┌────┴────┐ │
│ YES NO │
│ │ │ │
│ │ ├──► Delete heap memory
│ │ │ (actually free) │
│ │ │
│ ├──► - Transfer ownership to first ref
│ │ - Remove that ref from set
│ │ - Set ref's data_ to nullptr
│ │ (chain reaction continues) │
└──────────────────────────────────────┘
- Automatic Circular Reference Handling: No need for
weak_ptr- stack objects act as owners that force cleanup - Thread-Safe: Uses
std::mutexfor concurrent access protection - Move-Aware: Supports move semantics for efficient ownership transfer
- Transparent API: Similar interface to
std::shared_ptrwithoperator->,operator*,get()
# Clone the repository
git clone https://github.com/bridgeQiao/owner_atomic_shared_ptr
cd owner_atomic_shared_ptr
# Create build directory
mkdir build && cd build
# Configure and build (debug mode disabled by default)
cmake ..
make
# Enable debug output (shows ownership transfer, ref counting, etc.)
cmake -DOASP_DEBUG=ON ..
make
# Run tests
./examples/common_test#include "owner_atomic_shared_ptr.h"
#include <iostream>
struct Node {
oasp::OwnerAtomicSharedPtr<Node> next;
int value;
Node(int v) : value(v) {}
};
int main() {
// Create nodes with circular references
auto a = oasp::makeOwnerAtomicSharedPtr<Node>(1);
auto b = oasp::makeOwnerAtomicSharedPtr<Node>(2);
auto c = oasp::makeOwnerAtomicSharedPtr<Node>(3);
// Create a cycle: a -> b -> c -> a
a->next = b;
b->next = c;
c->next = a;
// No memory leak! When a, b, c go out of scope,
// the owner mechanism triggers chain cleanup:
// a (owner) -> b (new owner) -> c (new owner) -> delete
return 0;
}The implementation consists of three main components:
┌─────────────────────────────────────────────────────────────┐
│ Components │
├─────────────────────────────────────────────────────────────┤
│ ControlBlock (heap) │
│ ├── atomic<int> ctrl_ref_count // Control block ref count │
│ ├── int64_t owner // Current owner address │
│ ├── set<int64_t> ref_obj // Referencer addresses │
│ ├── mutex data_mut // Concurrent access lock │
│ └── void* data_ptr // Pointer to data object │
│ │
│ OwnerSharedPtrData<T> (heap) │
│ └── T value // Actual data │
│ │
│ OwnerAtomicSharedPtr<T> (stack/heap) │
│ ├── ControlBlock* control_ // Control block ptr │
│ └── T* value_ // Direct value access │
└─────────────────────────────────────────────────────────────┘
| Feature | std::shared_ptr | owner_atomic_shared_ptr |
|---|---|---|
| Circular References | ❌ Requires weak_ptr |
✅ Handled automatically |
| Reference Equality | All references equal | Distinguishes owner/reference |
| Performance | ⚡ Atomic operations | 🐌 Mutex overhead |
| Root Dependency | None | Requires stack root |
| Thread Safety | ✅ Atomic ops | ✅ Mutex protected |
-
Stack Dependency: Requires at least one stack object as root owner. Pure heap-only cycles can still leak.
-
Performance:
- Each copy requires mutex locking
std::setoperations have O(log n) complexity- Higher overhead than
std::shared_ptr
-
Non-Deterministic: Ownership transfer order depends on
std::setiteration order -
Debugging Complexity: Dynamic ownership transfer at runtime can be challenging to debug
owner_atomic_shared_ptr/
├── include/
│ ├── mem_manager.h # Memory object manager
│ └── owner_atomic_shared_ptr.h # Main smart pointer implementation
├── examples/
│ └── common_test.cpp # Test cases and examples
├── docs/
│ └── architecture.md # Detailed architecture documentation
├── CMakeLists.txt
└── README.md
The project includes comprehensive tests in examples/common_test.cpp:
- Basic Cycle Reference: A→B→C→A circular reference
- Concurrent Access: Multi-threaded stress test
- Control Block Lifecycle: Verify separation of control and data
- Move Semantics: Test move operations
For detailed architecture analysis and design principles, see docs/architecture.md.
MIT License