using std::unique_ptr with allocators

匿名 (未验证) 提交于 2019-12-03 01:20:02

问题:

I was trying my hand with allocators this time & felt that there were many chances of leaking the resources. So I thought what if I used std::unique_ptr to handle them. I tried my hand with a std::vector's allocator. My code goes like this :-

// allocator #include <iostream> #include <vector> #include <memory> using namespace std;  class X {     int x,ID;     static int i;     public:         X()         {             cout<<"constructing ";             ID=++i;             cout<<"ID="<<ID<<'\n';         }         X(int a)         {             x=a;             cout<<"constructing ";             ID=++i;             cout<<"ID="<<ID<<'\n';         }         void get()         {             cout<<"enter x: ";             cin>>x;         }         void disp()         {             cout<<"x="<<x<<'\t';         }         ~X()         {             cout<<"destroying ID="<<ID<<'\n';         } }; int X:: i=0;  int main() {     ios::sync_with_stdio(false);     vector<X> v;     auto alloc = v.get_allocator();     unsigned int i=0;      X *p(alloc.allocate(5));             for (i=0;i<5;++i)     alloc.construct (&p[i], i+1);     unique_ptr<X[]> ptr(p);      cout<<"\nthe elements are:-\n";     for (i=0;i<5;++i)     {         ptr[i].disp();         cout << '\t' << (long long)alloc.address(ptr[i]) << '\n';     }     cout<<"\n";      /*for (i=0;i<5;++i)     alloc.destroy(&p[i]);     deallocate(p,16)*/      return 0; }

Unfortunately this code crashes showing UB. So what should I do ? How should I manipulate my code so as to make it suited for std::unique_ptr ?

回答1:

template<typename T> std::unique_ptr<T[], std::function<void(T *)>> make_T(X *ptr, std::allocator<T> alloc, std::size_t size) {     auto deleter = [](T *p, std::allocator<T> alloc, std::size_t size) {         for (int i = 0; i < size; ++i) {             alloc.destroy(&p[i]);         }         alloc.deallocate(p, sizeof(T) * size);     };      return {ptr, std::bind(deleter, std::placeholders::_1, alloc, size)}; }    int main(int argc, const char * argv[]) {     std::allocator<X> alloc = std::allocator<X>();      X *p = alloc.allocate(5);     for (int i = 0; i < 5; ++i) {         alloc.construct(&p[i], i + 1);     }      auto ptr = make_T(p, alloc, 5);      return 0; }

Can also write one to construct the objects for you:

template<typename T, typename... Args> std::unique_ptr<T[], std::function<void(T *)>> make_T_Construct(std::allocator<T> alloc, std::size_t size, Args... args) {      X *ptr = alloc.allocate(size);      for (std::size_t i = 0; i < size; ++i) {         alloc.construct(&ptr[i], std::forward<Args>(args)...);     }       auto deleter = [](T *p, std::allocator<T> alloc, std::size_t size) {         for (std::size_t i = 0; i < size; ++i) {             alloc.destroy(&p[i]);         }         alloc.deallocate(p, sizeof(T) * size);     };      return {ptr, std::bind(deleter, std::placeholders::_1, alloc, size)}; }  int main(int argc, const char * argv[]) {     std::allocator<X> alloc = std::allocator<X>();      auto ptr = make_T(alloc, 5, 100);      return 0; }

Edit: To do what you want (tracking allocations), you have to track the memory allocations yourself using a custom allocator..

template<typename T> struct Allocator {     typedef T value_type;      Allocator() noexcept {};      template<typename U>     Allocator(const Allocator<U>& other) throw() {};      T* allocate(std::size_t n, const void* hint = 0)     {         T* memory = static_cast<T*>(::operator new(n * (sizeof(T) + sizeof(bool))));          for (std::size_t i = 0; i < n * (sizeof(T) + sizeof(bool)); ++i)         {             *reinterpret_cast<bool*>(reinterpret_cast<char*>(memory) + sizeof(bool)) = false;         }          return memory;     }      void deallocate(T* ptr, std::size_t n)     {         ::operator delete(ptr);     }      void construct(T* p, const T& arg)     {         destroy(p);         new(p) T(arg);         *reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = true;     }      template<class U, class... Args>     void construct(U* p, Args&&... args)     {         destroy(p);         ::new(p) U(std::forward<Args>(args)...);          *reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = true;     }      void destroy(T* p)     {         if (*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool))) {             p->~T();             *reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = false;         }     }      template<class U>     void destroy(U* p)     {         if (*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool))) {             p->~U();             *reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = false;         }     } };  template <typename T, typename U> inline bool operator == (const Allocator<T>&, const Allocator<U>&) {     return true; }  template <typename T, typename U> inline bool operator != (const Allocator<T>& a, const Allocator<U>& b) {     return !(a == b); }


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!