본문으로 건너뛰기
Previous
Next
C++ Custom Allocator | 'Custom Allocator' Guide

C++ Custom Allocator | 'Custom Allocator' Guide

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

  1. Custom allocator: Customize STL container memory management
  2. Basic structure: value_type, allocate(), deallocate()
  3. Use cases: Logging, pool, alignment, statistics
  4. 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

Master custom allocators for efficient memory management! 🚀


자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Development blog post organizing C++ Custom Allocator. template class MyAllocator { public: using value_type… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, allocator, memory, STL, custom 등으로 검색하시면 이 글이 도움이 됩니다.