This project offers a self-contained implementation of modern C++ smart pointers: unique_ptr, shared_ptr, and weak_ptr. Developed primarily as an educational exercise and a deep dive into the intricacies of memory management in C++, it aims to replicate the core functionalities and behavior of their std counterparts.
Beyond simply reimplementing the standard library features, smartPointers provides a robust test suite, including both comprehensive unit tests for correctness and detailed performance benchmarks comparing our custom raw:: pointers against std:: pointers. This allows for a direct evaluation of their efficiency and overhead.
Authored by NeKon69.
- Key Features
- Implemented Smart Pointers
- Technical Details
- Getting Started
- Performance Benchmarks
- Project Structure
- License
- Contact
- Complete Smart Pointer Trio: Full implementations of
raw::unique_ptr,raw::shared_ptr, andraw::weak_ptr. - Single Object and Array Support: All pointer types correctly handle both single objects (
T) and dynamic arrays (T[]). - Safe Factory Functions: Includes
raw::make_uniqueandraw::make_sharedfor safe, exception-aware, and efficient (forshared_ptr) object creation. - Thread-Safe Reference Counting:
raw::shared_ptrandraw::weak_ptrutilizestd::atomicfor thread-safe manipulation of use and weak counts. - Custom Control Block Optimization:
raw::make_sharedoptimizes memory allocation by allocating the object and its control block in a single contiguous memory region. - Comprehensive Unit Tests: Extensive test cases ensure the correctness and adherence to expected behavior for all smart pointer operations.
- Detailed Performance Benchmarks: In-depth comparisons against
std::unique_ptr,std::shared_ptr, andstd::weak_ptrto quantify performance characteristics. - Memory Leak Detection: Unit tests incorporate a counter for active
TestObjectinstances, verifying proper memory deallocation and absence of leaks.
Provides exclusive ownership of a dynamically allocated object or array. It implements move semantics, preventing copying, and ensures automatic deallocation when it goes out of scope.
Enables shared ownership of an object or array. It maintains a reference count (via a control block) to track how many shared_ptr instances point to the same resource. The resource is deallocated only when the last shared_ptr owning it is destroyed.
A non-owning "observer" smart pointer that can point to an object managed by a raw::shared_ptr without affecting its reference count. It's crucial for breaking circular references that would otherwise lead to memory leaks with shared_ptr. The lock() method can be used to safely obtain a shared_ptr if the observed object still exists.
- Language Standard: C++23
- Build System: CMake
- Concurrency Primitives:
std::atomicfor thread-safe reference counting. - Memory Management: Leverages
new/deleteforunique_ptrand custom allocation/deallocation routines (e.g.,std::aligned_alloc,std::free, placement new) forshared_ptrandweak_ptrcontrol blocks to optimize memory layout and performance. - Custom Deleters: Internal helper functions manage the correct destruction of single objects or arrays.
To build and run this project, you will need:
- A C++23 compatible compiler (e.g., GCC 13+, Clang 16+, MSVC 19.36+)
- CMake version 3.20 or higher
- Git
- Clone the repository:
git clone https://github.com/NeKon69/smartPointers.git cd smartPointers - Configure the build:
This command creates a
cmake -B build -S . -DCMAKE_BUILD_TYPE=Releasebuilddirectory and prepares the project files inside it for a Release build. - Compile the code:
This will compile all source files and generate the executable.
cmake --build build --config Release
The compiled executable automatically runs all unit tests and performance benchmarks.
- On Linux/macOS:
./build/smartPointers
- On Windows (if using Visual Studio build):
.\build\Release\smartPointers.exe
The output will show detailed results for each unit test and then present performance comparisons in a structured table.
The project includes a comprehensive set of benchmarks comparing raw:: smart pointers against their std:: counterparts. Each scenario is run for NUM_TRIALS (200) iterations with OPS_PER_TRIAL (1,000,000) operations. Results are presented in microseconds (us), showing minimum, maximum, and average durations, along with the percentage difference of raw vs std average time.
All benchmarks were performed on Arch Linux using GCC.
--- Performance Comparison Test: raw::unique_ptr vs std::unique_ptr ---
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Scenario | STD (us) | RAW (us) | Comparison | Active Objects Start/End
| Min Max Avg | Min Max Avg | RAW vs STD Avg (%) | Pre-test Post-test
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Make Single Object | 198 228 205 | 198 219 204 | -0.49 | 0 0
Make Array (size 1-10) | 10497 11908 10973 | 10373 14420 11382 | +3.73 | 0 0
Reset Single Object | 4235 5046 4747 | 4392 5023 4745 | -0.04 | 0 0
Reset Array | 11749 12456 12078 | 11902 12591 12231 | +1.27 | 0 0
Move Construct Single | 1026 1245 1067 | 1028 1174 1077 | +0.94 | 0 0
Move Assign Single | 600 634 609 | 417 596 434 | -28.74 | 0 0
Move Assign Array | 601 620 605 | 418 588 437 | -27.77 | 0 0
Access Single Object | 726 826 761 | 729 1138 791 | +3.94 | 0 0
Access Array Element | 1341 1548 1416 | 1339 1590 1408 | -0.56 | 0 0
Combined Stress Test | 2035 2083 2052 | 2056 2183 2088 | +1.75 | 0 0
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Performance comparison finished.
--- Performance Comparison Test: raw::shared_ptr vs std::shared_ptr ---
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Scenario | STD (us) | RAW (us) | Comparison | Active Objects Start/End
| Min Max Avg | Min Max Avg | RAW vs STD Avg (%) | Pre-test Post-test
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Make Single Object (make_shared) | 7284 8310 7647 | 6341 7731 6687 | -12.55 | 0 0
Make Array (make_shared, size 1-10) | 12770 14012 12952 | 12197 13943 12611 | -2.63 | 0 0
Reset Single Object | 5761 7314 6278 | 5303 6043 5612 | -10.61 | 0 0
Reset Array | 5904 6831 6183 | 5527 6925 5801 | -6.18 | 0 0
Move Construct Single | 7030 8419 7338 | 6619 7307 6828 | -6.95 | 0 0
Move Assign Single | 14380 15049 14563 | 13018 20432 13943 | -4.26 | 0 0
Move Assign Array | 23243 27527 24796 | 22911 28927 23539 | -5.07 | 0 0
Access Single Object | 739 1015 880 | 1668 2025 1794 | +103.86 | 0 0
Access Array Element | 3923 6323 4401 | 4267 5437 4508 | +2.43 | 0 0
Copy Construct Single | 12566 12757 12605 | 6472 6724 6645 | -47.28 | 0 0
Copy Assign Single | 1698 1936 1787 | 3201 3748 3308 | +85.11 | 0 0
Copy Assign Array | 3368 4526 3509 | 3411 3895 3565 | +1.60 | 0 0
Use Count | 297 372 347 | 198 378 233 | -32.85 | 0 0
Unique Check | 396 503 409 | 0 0 0 | -100.00 | 0 0
Combined Stress Test (Shared) | 21056 24045 21677 | 20797 22854 21193 | -2.23 | 0 0
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Performance comparison finished.
--- Performance Comparison Test: raw::weak_ptr vs std::weak_ptr ---
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Scenario | STD (us) | RAW (us) | Comparison | Active Objects Start/End
| Min Max Avg | Min Max Avg | RAW vs STD Avg (%) | Pre-test Post-test
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Weak from Shared Creation (Single) | 10742 10788 10752 | 1848 2330 1987 | -81.52 | 0 0
Weak from Shared Creation (Array) | 21815 27238 22418 | 12280 14129 12571 | -43.92 | 0 0
Weak Copy Construct | 18314 20496 18847 | 6637 9289 7169 | -61.96 | 0 0
Weak Move Construct | 18349 18474 18393 | 6273 7253 6564 | -64.31 | 0 0
Weak Copy Assign | 20522 21337 20749 | 13511 14470 13715 | -33.90 | 0 0
Weak Move Assign | 20672 21704 20923 | 13001 13409 13076 | -37.50 | 0 0
Weak Shared Assign (Single) | 18314 19253 18603 | 6417 6754 6606 | -64.49 | 0 0
Weak Shared Assign (Array) | 21911 23556 22308 | 12383 12661 12444 | -44.22 | 0 0
Weak Reset | 8463 9292 8642 | 6307 7049 6553 | -24.17 | 0 0
Weak Swap | 23132 24202 23405 | 12733 12869 12782 | -45.39 | 0 0
Weak Use Count | 249 372 293 | 198 227 201 | -31.40 | 0 0
Weak Expired | 4608 4984 4708 | 4679 4865 4787 | +1.68 | 0 0
Weak Lock (Single) | 8609 8774 8688 | 4605 4724 4667 | -46.28 | 0 0
Weak Lock (Array) | 9046 9953 9188 | 7685 7841 7745 | -15.71 | 0 0
Combined Stress Test (Weak) | 20790 21443 20913 | 20449 21324 20687 | -1.08 | 0 0
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
These benchmarks highlight several key observations:
raw::unique_ptr: Generally performs very close tostd::unique_ptr. Our custom implementation shows a noticeable performance advantage in move assignment scenarios (both single objects and arrays), while other operations are comparable or slightly slower. This suggests a lean design with minimal overhead.raw::shared_ptr:make_shared,reset, andcopy constructoperations forraw::shared_ptrshow performance advantages compared tostd::shared_ptr.use_count()andunique()checks are also reported as significantly faster forraw. However, operations likecopy assignandaccess single objectare notably slower forraw::shared_ptr. This indicates a mixed performance profile, where efficiency varies depending on the specific operation.raw::weak_ptr: In the vast majority of tested operations, including creation from shared pointers, copy/move construction/assignment, reset, swap, use count, and lock,raw::weak_ptrdemonstrates significantly lower execution times (i.e., faster performance) thanstd::weak_ptr. Theexpired()check is the only operation whereraw::weak_ptris slightly slower.
Overall, the benchmarks suggest that raw::unique_ptr is highly competitive and faster in specific scenarios. raw::weak_ptr appears to outperform std::weak_ptr in almost all measured operations according to this data. raw::shared_ptr shows advantages in some key operations (like creation and reset) but is slower in others (like copy assignment and single object access), resulting in a mixed performance profile compared to its std:: counterpart.
The project is organized into the following main directories:
include/raw/: Contains all public header files defining theraw::smart pointer classes (fwd.h,hub.h,helper.h,smart_ptr_base.h,unique_ptr.h,shared_ptr.h,weak_ptr.h).raw_memory.hserves as a convenient single-include header.tests/: Houses the unit tests (unit_unique.h,unit_shared.h,unit_weak.h) and performance benchmarks (benchmark_unique.h,benchmark_shared.h,benchmark_weak.h,common_test_utils.h,run_all_tests.h) for the smart pointer implementations.CMakeLists.txt: The main CMake build configuration file for the project.main.cpp: The entry point for running all tests and benchmarks.
This project is licensed under the MIT License. See the LICENSE file for details.
If you have any questions, suggestions, or encounter issues, feel free to reach out:
- GitHub Issues: https://github.com/NeKon69/smartPointers/issues
- Email: nobodqwe@gmail.com