Advertisement
ilyabelow

Untitled

Jun 16th, 2019
311
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.93 KB | None | 0 0
  1. #include <new>
  2.  
  3. template<typename T>
  4. class unique_ptr {
  5. private:
  6.     T *ptr;
  7. public:
  8.     unique_ptr(T *ptr) : ptr(ptr) {}
  9.  
  10.     unique_ptr(const unique_ptr &) = delete;
  11.  
  12.     unique_ptr(unique_ptr &&another) noexcept {
  13.         ptr = another.ptr;
  14.         another.ptr = nullptr;
  15.     };
  16.  
  17.     //Copying is not allowed
  18.     unique_ptr &operator=(const unique_ptr &) = delete;
  19.  
  20.     unique_ptr &operator=(unique_ptr &&another) & noexcept {
  21.         ~unique_ptr();
  22.         ptr = another.ptr;
  23.         another.ptr = nullptr;
  24.     };
  25.  
  26.     T &operator*() const {
  27.         return *ptr;
  28.     }
  29.  
  30.     T *operator->() const noexcept {
  31.         return ptr;
  32.     }
  33.  
  34.     ~unique_ptr() {
  35.         delete ptr;
  36.     }
  37. };
  38.  
  39. template<typename T>
  40. struct inner_ptr {
  41.     T *ptr = nullptr; //Pointer to the object itself
  42.     unsigned int shared_counter = 0; //how much shared_ptr is pointing to ptr
  43.     unsigned int weak_counter = 0; //how much weak_ptr is pointing to ptr
  44.     bool made = false;  //was shared_ptr constructed by make_shared or in ordinary way
  45.  
  46. };
  47.  
  48. template<typename T>
  49. struct shared_ptr {
  50.     //inner_ptr houses counter for how much shared_ptrs with common raw ptr exist
  51.  
  52.     inner_ptr<T> *inner;
  53.  
  54.     shared_ptr() = default;
  55.  
  56.     shared_ptr(inner_ptr<T> *inner) : inner(inner) {
  57.         inner->shared_counter++;
  58.     }
  59.  
  60.     //When constructing shared ptr from raw ptr, new 'colony' of shared_ptrs is created with new inner
  61.     shared_ptr(T *ptr) {
  62.         inner = new inner_ptr<T>;
  63.         inner->shared_counter = 1;
  64.         inner->ptr = ptr;
  65.     }
  66.  
  67.     //inner_ptr is constructed on already allocated place - inner_ptr
  68.     shared_ptr(T *ptr, void *inner_new) {
  69.         inner = new(inner_new) inner_ptr<T>;
  70.         inner->shared_counter = 1;
  71.         inner->ptr = ptr;
  72.         inner->made = true;
  73.     }
  74.  
  75.     //Copy raw poiner, but increase shared_ptrs counter
  76.     shared_ptr(const shared_ptr &another) {
  77.         inner = another.inner;
  78.         inner->shared_counter++;
  79.     }
  80.  
  81.     //Copy pointer, but don't alter counter because we erase pointer from the old object
  82.     shared_ptr(shared_ptr &&another) noexcept {
  83.         inner = another.inner;
  84.         another.inner = nullptr;
  85.     }
  86.  
  87.     //Copy and swap logic: copy logic from constructor is used to avoid copypaste, old object destructs automatically
  88.     //It is efficient in case of complicated copy and destruction logic
  89.     shared_ptr &operator=(const shared_ptr &another) &{
  90.         if (&another == this) {
  91.             return *this;
  92.         }
  93.         shared_ptr copy(another);
  94.         std::swap(copy, *this);
  95.         return *this;
  96.     }
  97.  
  98.     //Same, but with noexcept
  99.     shared_ptr &operator=(shared_ptr &&another) & noexcept {
  100.         if (&another == this) {
  101.             return *this;
  102.         }
  103.         shared_ptr copy(another);
  104.         std::swap(copy, *this);
  105.         return *this;
  106.     }
  107.  
  108.     T &operator*() const {
  109.         return *(inner->ptr);
  110.     }
  111.  
  112.     T *operator->() const noexcept {
  113.         return inner->ptr;
  114.     }
  115.  
  116.     ~shared_ptr() {
  117.         inner->shared_counter--;
  118.         //Memory is cleaned only when there is no shared_ptrs left that hold the same raw pointer
  119.         if (inner->shared_counter == 0) {
  120.             if (inner->weak_counter == 0) {
  121.                 //If shared_ptr is made from make_shared, then we can deallocate only one chunk of memory
  122.                 if (inner->made) {
  123.                     inner->ptr->~T();
  124.                     operator delete(inner, sizeof(inner_ptr<T>) + sizeof(T));
  125.                 } else {
  126.                     delete inner->ptr;
  127.                     delete inner;
  128.                 }
  129.             } else {
  130.                 delete inner->ptr;
  131.             }
  132.         }
  133.     }
  134. };
  135.  
  136. template<typename T>
  137. struct weak_ptr {
  138.     inner_ptr<T> *helper;
  139.  
  140.     weak_ptr(const shared_ptr<T> &ptr) {
  141.         helper = ptr.inner;
  142.         ptr.inner->weak_counter++;
  143.     }
  144.  
  145.     /* standard copy/move constructors/assignment operators */
  146.  
  147.     bool expired() const {
  148.         return helper->shared_counter == 0;
  149.     }
  150.  
  151.     shared_ptr<T> lock() const {
  152.         if (expired()) {
  153.             return shared_ptr<T>();
  154.         }
  155.         return shared_ptr(&helper);
  156.     }
  157.  
  158.     ~weak_ptr() {
  159.         helper->weak_counter--;
  160.         if (helper->weak_counter == 0 && helper->shared_counter == 0) {
  161.             delete helper;
  162.         }
  163.  
  164.     }
  165. };
  166.  
  167. template<typename T, typename... Args>
  168. unique_ptr<T> make_unique(Args &&... args) {
  169.     return unique_ptr(new T(std::forward<Args>(args)...));
  170. }
  171.  
  172. template<typename T, typename... Args>
  173. shared_ptr<T> make_shared(Args &&... args) {
  174.     //allocate big chunk of memory for object and inner together
  175.     char *p = new char[sizeof(T) + sizeof(inner_ptr<T>)];
  176.     //Construct object
  177.     T *ptr = new(p + sizeof(inner_ptr<T>)) T(std::forward<Args>(args)...);
  178.     //Construct tweaked shared_ptr constructor that constructs inner_ptr on preallocated memory
  179.     return shared_ptr(ptr, p);
  180. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement