Writing a simple cpp allocator
Last year I had joined BSC to work on my master’s thesis, my goal was to replace the standard cpp allocator with a custom allocator which would allocate to heterogenous memory systems automatically.
It was the first time for me to write a custom allocator in cpp.Here is how I did it.
#include <iostream> using namespace std; template<class T> struct TestAllocator { typedef T value_type; TestAllocator() noexcept; template<class U> TestAllocator(const TestAllocator <U> &) noexcept {} template<class U> bool operator==(const TestAllocator<U> &) const noexcept { return true; } template<class U> bool operator!=(const TestAllocator<U> &) const noexcept { return false; } T *allocate(const size_t n) const; void deallocate(T *const p, size_t) const noexcept; }; template<class T> T *TestAllocator<T>::allocate(const size_t n) const { if (n == 0) { return nullptr; } if (n > static_cast<size_t>(-1) / sizeof(T)) { throw std::bad_array_new_length(); } void *baseptr = malloc(n); if (!baseptr){ throw std::bad_alloc(); } return static_cast<T *>(baseptr); } template<class T> void TestAllocator<T>::deallocate(T *const p, size_t) const noexcept { free(p); } template<class T> TestAllocator<T>::TestAllocator() noexcept { }
One of the issues I faced was not declaring typedef T value_type
for the class template.The error message that would be returned by the compiler was not easy to comprehend
/usr/include/c++/11/bits/stl_vector.h:1582:75: error: ‘_M_get_Tp_allocator’ was not declared in this scope; did you mean ‘get_allocator’? 1582 | = this->_M_allocate(_S_check_init_len(__n, _M_get_Tp_allocator())); | ~~~~~~~~~~~~~~~~~~~^~ | get_allocator /usr/include/c++/11/bits/stl_vector.h:1583:25: error: ‘struct std::_Vector_base<int, TestAllocator<int> >::_Vector_impl’ has no member named ‘_M_end_of_storage’ 1583 | this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; | ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~ /usr/include/c++/11/bits/stl_vector.h:1583:59: error: ‘struct std::_Vector_base<int, TestAllocator<int> >::_Vector_impl’ has no member named ‘_M_start’ 1583 | this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; | ~~~~~~~~~~~~~~^~~~~~~~ /usr/include/c++/11/bits/stl_vector.h:1584:25: error: ‘struct std::_Vector_base<int, TestAllocator<int> >::_Vector_impl’ has no member named ‘_M_finish’ 1584 | this->_M_impl._M_finish = | ~~~~~~~~~~~~~~^~~~~~~~~ /usr/include/c++/11/bits/stl_vector.h:1586:55: error: ‘struct std::_Vector_base<int, TestAllocator<int> >::_Vector_impl’ has no member named ‘_M_start’ 1586 | this->_M_impl._M_start,
Looking at the stl_vector.h
file we come across the following which gave me the hint that we are expecting the missing type information.
/usr/include/c++/11/bits/stl_vector.h
128 struct _Vector_impl 129 : public _Tp_alloc_type, public _Vector_impl_data ... ... 246 private: 247 _Vector_impl& _M_impl; ... 279 const _Tp_alloc_type& 280 _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT 281 { return this->_M_impl; } ... 293 _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT 294 : _M_impl(__a) { } ... 397 __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept)
Now we can use it to replace any standard library class.
int main() { vector<int, TestAllocator<int>> test { 10, 10, 10,10,10,10,10 }; for(int i: test){ cout << i << endl; } return 0; }