C++ Custom Allocator | 'Custom Allocator' Guide
이 글의 핵심
template<typename T> class MyAllocator { public: using value_type = T; T allocate(size_t n) { return…
What is Custom Allocator?
STL container memory management
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
template<typename T>
class MyAllocator {
public:
using value_type = T;
T* allocate(size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
::operator delete(p);
}
};
// Usage
std::vector<int, MyAllocator<int>> vec;
Basic Structure
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
template<typename T>
class Allocator {
public:
using value_type = T;
Allocator() = default;
template<typename U>
Allocator(const Allocator<U>&) {}
T* allocate(size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
::operator delete(p);
}
};
template<typename T, typename U>
bool operator==(const Allocator<T>&, const Allocator<U>&) {
return true;
}
template<typename T, typename U>
bool operator!=(const Allocator<T>&, const Allocator<U>&) {
return false;
}
Practical Examples
Example 1: Logging Allocator
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
template<typename T>
class LoggingAllocator {
public:
using value_type = T;
T* allocate(size_t n) {
std::cout << "Allocate: " << n << " * " << sizeof(T) << " bytes" << std::endl;
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
std::cout << "Deallocate: " << n << " * " << sizeof(T) << " bytes" << std::endl;
::operator delete(p);
}
};
int main() {
std::vector<int, LoggingAllocator<int>> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
}
Example 2: Pool Allocator
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality, ensure stability through error handling, and perform branching with conditionals. Understand the role of each part while examining the code.
template<typename T>
class PoolAllocator {
MemoryPool* pool;
public:
using value_type = T;
PoolAllocator(MemoryPool* p) : pool(p) {}
template<typename U>
PoolAllocator(const PoolAllocator<U>& other) : pool(other.pool) {}
T* allocate(size_t n) {
if (n != 1) {
throw std::bad_alloc();
}
return static_cast<T*>(pool->allocate());
}
void deallocate(T* p, size_t n) {
pool->deallocate(p);
}
template<typename U>
friend class PoolAllocator;
};
int main() {
MemoryPool pool(sizeof(int), 100);
std::vector<int, PoolAllocator<int>> vec{&pool};
}
Example 3: Aligned Allocator
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality, ensure stability through error handling, and perform branching with conditionals. Understand the role of each part while examining the code.
template<typename T, size_t Alignment = 64>
class AlignedAllocator {
public:
using value_type = T;
T* allocate(size_t n) {
void* ptr = aligned_alloc(Alignment, n * sizeof(T));
if (!ptr) {
throw std::bad_alloc();
}
return static_cast<T*>(ptr);
}
void deallocate(T* p, size_t n) {
free(p);
}
};
int main() {
// 64-byte alignment
std::vector<float, AlignedAllocator<float, 64>> vec;
}
Example 4: Statistics Allocator
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
template<typename T>
class StatsAllocator {
static inline size_t allocCount = 0;
static inline size_t deallocCount = 0;
static inline size_t bytesAllocated = 0;
public:
using value_type = T;
T* allocate(size_t n) {
++allocCount;
bytesAllocated += n * sizeof(T);
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
++deallocCount;
::operator delete(p);
}
static void printStats() {
std::cout << "Allocations: " << allocCount << std::endl;
std::cout << "Deallocations: " << deallocCount << std::endl;
std::cout << "Bytes: " << bytesAllocated << std::endl;
}
};
Allocator Requirements
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
template<typename T>
class Allocator {
public:
// Required
using value_type = T;
T* allocate(size_t n);
void deallocate(T* p, size_t n);
// Optional
template<typename U>
Allocator(const Allocator<U>&);
// Comparison
bool operator==(const Allocator&) const;
bool operator!=(const Allocator&) const;
};
Summary
Key Points
- Custom allocator: Customize STL container memory management
- Basic structure:
value_type,allocate(),deallocate() - Use cases: Logging, pool, alignment, statistics
- Requirements: Must implement required interface
When to Use
✅ Use custom allocator when:
- Need memory pool
- Need aligned allocation
- Need allocation tracking/profiling
- Need custom memory management
❌ Don’t use when:
- Default allocator is sufficient
- Adds unnecessary complexity
- Performance gain is negligible
Best Practices
- ✅ Implement required interface correctly
- ✅ Handle exceptions properly
- ✅ Consider allocator equality
- ❌ Don’t make allocators too complex
- ❌ Don’t forget thread safety if needed
Related Articles
Master custom allocators for efficient memory management! 🚀
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Development blog post organizing C++ Custom Allocator. template
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
이 글에서 다루는 키워드 (관련 검색어)
C++, allocator, memory, STL, custom 등으로 검색하시면 이 글이 도움이 됩니다.