无指针算术运算的自定义分配器实现技术咨询
替代指针算术的自定义分配器实现
Great question! Pointer arithmetic can feel clunky and error-prone, so ditching it for safer, more readable integer-based address calculation is a smart move. Here's how you can rewrite your allocator to avoid direct pointer arithmetic entirely:
Key Approach: Use Integer-Based Address Calculation
Instead of manipulating pointers directly, we'll convert our memory block's address to a uintptr_t (a standard integer type designed to hold pointer values) and perform all calculations using integers. This avoids undefined behavior risks associated with pointer arithmetic and makes the logic more explicit.
Full Rewritten Allocator Class
#include <cstdint> #include <cstddef> #include <utility> // for std::move class allocator { private: std::byte* memory; // Use std::byte instead of char for clearer memory semantics (C++17+) std::ptrdiff_t offset; std::size_t total_size; public: // Constructor: Allocate the underlying memory block allocator(std::size_t size) : total_size(size), offset(0) { memory = new std::byte[size]; } // Destructor: Clean up the allocated memory ~allocator() { delete[] memory; } // Disable copy operations to prevent double-free errors allocator(const allocator&) = delete; allocator& operator=(const allocator&) = delete; // Enable move operations for efficient transfers allocator(allocator&& other) noexcept : memory(other.memory), offset(other.offset), total_size(other.total_size) { other.memory = nullptr; other.offset = 0; other.total_size = 0; } allocator& operator=(allocator&& other) noexcept { if (this != &other) { delete[] memory; memory = other.memory; offset = other.offset; total_size = other.total_size; other.memory = nullptr; other.offset = 0; other.total_size = 0; } return *this; } // Allocate method without pointer arithmetic void* allocate(std::size_t size, std::size_t alignment) { // Calculate the current starting address as an integer uintptr_t current_addr = reinterpret_cast<uintptr_t>(memory) + offset; // Calculate the aligned address (standard alignment logic using integers) uintptr_t aligned_addr = (current_addr + alignment - 1) & ~(static_cast<uintptr_t>(alignment) - 1); // Calculate padding needed to reach the aligned address std::size_t padding = static_cast<std::size_t>(aligned_addr - current_addr); // Check if we have enough remaining space for padding + requested size if (static_cast<std::size_t>(offset) + padding + size > total_size) { return nullptr; // Not enough space, allocation fails } // Update the offset to reflect the used space offset += padding + static_cast<std::ptrdiff_t>(size); // Convert the aligned integer address back to a void pointer return reinterpret_cast<void*>(aligned_addr); } // Optional: Add a deallocate method if needed (simplified example) void deallocate(void* ptr, std::size_t size) { // For a simple linear allocator like this, deallocation might be no-op // Or you could track free blocks if implementing a more complex allocator } };
What Changed & Why:
std::byteinstead ofchar:charis intended for character data, whilestd::byteis explicitly designed for raw memory operations, making the code more semantically clear.- Integer-based address calculation: By converting pointers to
uintptr_t, all calculations are done with integers instead of pointer arithmetic. This avoids issues like pointer type mismatches and undefined behavior from invalid pointer operations. - Proper resource management: Added a destructor, disabled copy operations, and implemented move semantics to prevent memory leaks and double-free errors (critical for any allocator).
- Explicit alignment logic: The alignment calculation uses standard integer bitmasking, which is portable and easy to follow.
Notes:
- If you're working with C++ versions before C++17, replace
std::bytewithunsigned char(it's the closest equivalent for raw memory operations). - For a production-grade allocator, you'd likely want to add error handling (like throwing
std::bad_allocinstead of returningnullptr) and possibly adeallocatemethod that properly manages free blocks (if moving beyond a simple linear allocator).
内容的提问来源于stack exchange,提问作者Mike van Dyke
相关产品推荐
相关产品推荐

