Implementando una clase Shared_PTR en C ++ -- ++ campo con c++11 campo con reinventing-the-wheel campo con pointers camp codereview Relacionados El problema

Implementing a shared_ptr class in C++


4
vote

problema

Español

Estoy tratando de escribir mi propia implementación shared_ptr / débil_ptr en C ++. Tengo los siguientes requisitos:

No necesito soporte para lo siguiente:

  • multithreading (sincronización)
  • Soporte para tipos polimórficos como el tipo plantelado de Shared_PTR (como Shared_PTR BASE *)

Razones para querer escribir mi propia implementación:

  • necesita suministrar un asignador separado para el bloque de control
  • necesita reducir el tamaño del bloque de control (la versión estándar tiene un bloque de control muy grande debido a su soporte para el multiprito y el polimorfismo entre otras cosas)

Preocupaciones:

  • Estoy preocupado por usar mi implementación actual en el Código de Producción (necesita algunas sugerencias sobre la mejor manera de probarlo a fondo)
  • A LO A LO PERMITIDO PUEDO HAZ QUE DESEJAR LAS CARACTERÍSTICAS IMPORTANTES DE MI IMPLEMENTACIÓN

La siguiente es lo que he escrito hasta ahora (compilable en un compilador compatible con C ++ 11, con la función principal y el ejemplo):

  @Test public void decodeTests() throws DecoderException {     assertThat(decode(Hex.decodeHex("f4f29c9e769f1b".toCharArray()))).isEqualTo("testing");     assertThat(decode(Hex.decodeHex("31D98C56B3DD70".toCharArray()))).isEqualTo("12345678");     assertThat(decode(Hex.decodeHex("6176D94DAFCB1B".toCharArray()))).isEqualTo("alentur");     assertThat(decode(Hex.decodeHex("61F79B8E2ECB5B657CB80D679701E77638CD768DDF6D".toCharArray()))).isEqualTo("another-example@gmail.com"); } 2  
Original en ingles

I'm trying to write my own shared_ptr/weak_ptr implementation in C++. I have the following requirements:

I do NOT need support for the following:

  • multithreading (synchronisation)
  • support for polymorphic types as the templated type of the shared_ptr (such as shared_ptr Base*)

Reasons for wanting to write my own implementation:

  • need to supply a separate allocator for the control block
  • need to reduce the size of the control block (the standard version has a very large control block due to its support for multithreading and polymorphism among other things)

Concerns:

  • I'm worried about using my current implementation in production code (need some suggestions on how best to thoroughly test it)
  • I'm concerned I may have left out important features from my implementation

The following is what I've written so far (compilable in a C++11 compliant compiler, with main function and example):

#include <iostream> #include <memory>  struct shared_ptr_control_base {     virtual ~shared_ptr_control_base() { }      void decrement_count_shared() noexcept { m_shared--; }     void increment_count_shared() noexcept { m_shared++; }      void decrement_count_weak() noexcept { m_weak--; }     void increment_count_weak() noexcept { m_weak++; }      virtual void                     destroy_shared(void*)       noexcept = 0;     virtual void                     destruct()                  noexcept = 0;     virtual shared_ptr_control_base* create()              const          = 0;      uint32_t m_shared = 1;     uint32_t m_weak   = 0; };  template <typename SharedType, typename AllocatorType> struct shared_ptr_control_derived : shared_ptr_control_base {     shared_ptr_control_derived() = delete;     shared_ptr_control_derived(AllocatorType a_allocator) : m_allocator(a_allocator) { }      shared_ptr_control_derived<SharedType, AllocatorType>* create() const     {         auto l_alloctor = std::allocator<shared_ptr_control_derived<SharedType, AllocatorType>>();         auto l_p = l_alloctor.allocate(1);         l_alloctor.construct(l_p, *this);         return l_p;     }      void destroy_shared(void* a_pointer) noexcept     {         m_allocator.destroy(static_cast<SharedType*>(a_pointer));         m_allocator.deallocate(static_cast<SharedType*>(a_pointer), 1);     }      void destruct() noexcept     {         auto l_alloctor = std::allocator<shared_ptr_control_derived<SharedType, AllocatorType>>();         l_alloctor.destroy(this);         l_alloctor.deallocate(this, 1);     }      mutable AllocatorType m_allocator; };  template <typename SharedType> struct shared_ptr;  template <typename SharedType> struct weak_ptr {     friend struct shared_ptr<SharedType>;      weak_ptr() : m_pointer(nullptr), m_control(nullptr) { }      weak_ptr(const weak_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(const weak_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_weak();         }     }      weak_ptr(weak_ptr<SharedType>&& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(shared_ptr<T>&&)" << std::endl;          a_that.m_pointer = nullptr;         a_that.m_control = nullptr;     }      weak_ptr(const shared_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(const shared_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_weak();         }     }      weak_ptr<SharedType>& operator=(const weak_ptr<SharedType>& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (const weak_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_weak(); }         }          return *this;     }      weak_ptr<SharedType>& operator=(weak_ptr<SharedType>&& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (weak_ptr<T>&&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }         }          m_pointer = a_rhs.m_pointer;         m_control = a_rhs.m_control;         a_rhs.m_pointer = nullptr;         a_rhs.m_control = nullptr;          return *this;     }      weak_ptr<SharedType>& operator=(const shared_ptr<SharedType>& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (const shared_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_weak(); }         }          return *this;     }      ~weak_ptr()     {         if (m_control) { decrement_destruct(); }     }      void decrement_destruct()     {         m_control->decrement_count_weak();          if (m_control->m_weak == 0)         {             if (m_control->m_shared == 0)             {                 std::cout << "weak_ptr -> destructing control block" << std::endl;                  m_control->destruct();             }         }     }      SharedType* operator->() const noexcept { return m_pointer; }      SharedType& operator*() const noexcept { return *m_pointer; }      explicit operator bool() const noexcept { return m_control ? m_control->m_shared : false; }      uint32_t use_count() const noexcept { return m_control ? m_control->m_shared : 0; }      SharedType* get() const noexcept { return m_pointer; };  private:     SharedType* m_pointer;     shared_ptr_control_base* m_control; };  template <typename SharedType> struct shared_ptr {     friend struct weak_ptr<SharedType>;      shared_ptr() : m_pointer(nullptr), m_control(nullptr) { }      explicit shared_ptr(SharedType* const a_pointer) :         m_pointer(a_pointer),         m_control(nullptr)     {         std::cout << "shared_ptr<T>::shared_ptr(T*)" << std::endl;          if (m_pointer != nullptr) { create_control(std::allocator<SharedType>()); }     }      template <typename AllocatorType> explicit shared_ptr(SharedType* const a_pointer, const AllocatorType a_allocator) :         m_pointer(a_pointer),         m_control(nullptr)     {         if (m_pointer != nullptr) { create_control(a_allocator); }     }      shared_ptr(const shared_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "shared_ptr<T>::shared_ptr(const shared_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_shared();         }     }      shared_ptr<SharedType>& operator=(const shared_ptr<SharedType>& a_rhs)     {         std::cout << "shared_ptr<T>& shared_ptr<T>::operator = (const shared_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_shared(); }         }          return *this;     }      ~shared_ptr()     {         if (m_control) { decrement_destruct(); }     }      SharedType* operator->() const noexcept { return m_pointer; }      SharedType& operator*() const noexcept { return *m_pointer; }      explicit operator bool() const noexcept { return m_pointer != nullptr; }      uint32_t use_count() const noexcept { return m_control ? m_control->m_shared : 0; }      void decrement_destruct()     {         m_control->decrement_count_shared();          if (m_control->m_shared == 0)         {             std::cout << "shared_ptr -> destructing shared object" << std::endl;              m_control->destroy_shared(m_pointer);              if (m_control->m_weak == 0) { std::cout << "shared_ptr -> destructing control block" << std::endl; m_control->destruct(); }         }     }      void reset() noexcept { shared_ptr<SharedType>().swap(*this); }      void reset(SharedType* const a_pointer) noexcept { shared_ptr<SharedType>(a_pointer).swap(*this); }      void swap(shared_ptr<SharedType>& a_that) noexcept { std::swap(m_pointer, a_that.m_pointer); std::swap(m_control, a_that.m_control); }      template <typename AllocatorType> void create_control(AllocatorType a_allocator)     {         m_control = shared_ptr_control_derived<SharedType, AllocatorType>(a_allocator).create();     }      SharedType* get() const noexcept { return m_pointer; };  private:     SharedType* m_pointer;     shared_ptr_control_base* m_control; };  int* allocate(const int a_argument) {     std::allocator<int> l_a;     auto l_p = l_a.allocate(1);     l_a.construct(l_p, a_argument);     return l_p; }  int main() {     // don't use this yet, as it might crash the program     weak_ptr<int> weak_1;      {         // allocate memory for an int, and take shared ownership of the memory in the shared_ptr         shared_ptr<int> shared_1(allocate(42));          // set the weak_ptr to refer to the memory in the shared_ptr;         weak_1 = shared_1;          if (weak_1)         {             std::cout << "weak_1 is safe to use" << std::endl;              *(weak_1.get()) = 47;             *weak_1 = 42;             std::cout << *weak_1 << std::endl;         }     }      // shared_1 went out of scope, so was destroyed     std::cout << "weak_1 control block's shared count: " << weak_1.use_count() << std::endl;      if (!weak_1)     {         std::cout << "weak_1 is NOT safe to use" << std::endl;     } } 
           
       
       

Lista de respuestas

4
 
vote
vote
La mejor respuesta
 

Lo mejor que tiene que ver son excepciones que le harán fugarse.

      auto l_p = l_alloctor.allocate(1);     l_alloctor.construct(l_p, *this);   // What happens if this throws?     return l_p;      // Need to make sure you re-clain the memory      auto l_p = l_alloctor.allocate(1);     try {         l_alloctor.construct(l_p, *this);     }     catch(..) {         l_alloctor.deallocate(l_p);         throw;     }     return l_p;   

El std::allocator LLAMADA construct() no necesita dos argumentos.

      l_alloctor.construct(l_p, *this);      // This results in a call to:     new (lp) SharedType(std::forward<shared_ptr_control_derived<T,A>>(*this));   

Esto significa que el tipo que está compartiendo debe tener un constructor que realice un asignador como un parámetro. No necesitas hacer esto (ya que C ++ 11). Solo necesitas pasar el puntero (que creo que es lo que realmente quieres).

       l_alloctor.construct(l_p); // See: http://en.cppreference.com/w/cpp/memory/allocator/construct   

¿Por qué estás creando asignadores en cada llamada de función?

      auto l_alloctor = std::allocator<shared_ptr_control_derived<SharedType, AllocatorType>>();   

Esto funciona para los asignadores simples que usan el montón estándar de C ++. Pero algunos asignadores mantienen al estado (asignadores de piscinas). Usted debe usar el mismo objeto asignador para asignar / crear / eliminar / desatificar. Y ya tiene un objeto de asignación local almacenado localmente m_allocator , así que use eso.

Su create() y destruct()8 El uso no va a funcionar bien porque no necesariamente usan el mismo objeto asignador (como se copia el asignador). Así que necesita volver a trabajar todos los escenarios de uso para esto. Yo personalmente haría estos dos métodos estática.

 

Big thing you have to watch are exceptions that will cause you to leak.

    auto l_p = l_alloctor.allocate(1);     l_alloctor.construct(l_p, *this);   // What happens if this throws?     return l_p;      // Need to make sure you re-clain the memory      auto l_p = l_alloctor.allocate(1);     try {         l_alloctor.construct(l_p, *this);     }     catch(..) {         l_alloctor.deallocate(l_p);         throw;     }     return l_p; 

The std::allocator call construct() does not need two arguments.

    l_alloctor.construct(l_p, *this);      // This results in a call to:     new (lp) SharedType(std::forward<shared_ptr_control_derived<T,A>>(*this)); 

This means the type you are sharing must have a constructor that takes an allocator as a parameter. You don't need to do this (since C++11). You only need to pass the pointer (which I think is what you actually want).

     l_alloctor.construct(l_p); // See: http://en.cppreference.com/w/cpp/memory/allocator/construct 

Why are you creating allocators on each function call?

    auto l_alloctor = std::allocator<shared_ptr_control_derived<SharedType, AllocatorType>>(); 

This works for simple allocators that use the standard C++ heap. But some allocators keep state (pool allocators). You must use the same allocator object to allocate/create/delete/de-allocate. And you already have a local allocator object stored locally m_allocator so use that.

Your create() and destruct() usage are not going to work well because they don't necessarily use the same allocator object (as the allocator is copied). SO you need to re-work all the use scenarios for this. I would personally make these two methods static.

 
 
0
 
vote

He realizado algunos cambios en mi código basado en sugerencias de Loki Astari:

  • Soporte agregado para mudar los asignadores en el objeto Shared_PTR mediante el uso de una función Make_Shared
  • Soporte añadido para la seguridad de excepción con bloques de intento / captura (en la función Make_Shared)
  • Código eliminado para los asignadores de instancias cada vez que se llama a una función (mientras que yo mismo uso a los asequipadores, sería bueno apoyarlos si es posible)

  #include <iostream> #include <memory>  struct shared_ptr_control_base {     virtual ~shared_ptr_control_base() { }      void decrement_count_shared() noexcept { m_shared--; }     void increment_count_shared() noexcept { m_shared++; }      void decrement_count_weak() noexcept { m_weak--; }     void increment_count_weak() noexcept { m_weak++; }      virtual void destroy_shared(void*) noexcept = 0;     virtual void destruct()            noexcept = 0;      uint32_t m_shared = 1;     uint32_t m_weak   = 0; };  template <typename AllocatorTypeControl, typename AllocatorTypeShared, typename SharedType> struct shared_ptr_control_derived : shared_ptr_control_base {     shared_ptr_control_derived() = delete;     shared_ptr_control_derived(const shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&) = delete;      shared_ptr_control_derived(shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&& a_that) :         m_allocatorControl(std::move(a_that.m_allocatorControl)),         m_allocatorShared(std::move(a_that.m_allocatorShared))     {      }      shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&         operator = (const shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&) = delete;     shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&         operator = (shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&&) = delete;      shared_ptr_control_derived(AllocatorTypeControl&& a_allocatorC,                                AllocatorTypeShared&& a_allocatorS) :         m_allocatorControl(a_allocatorC),         m_allocatorShared(a_allocatorS)     {      }      void destroy_shared(void* a_pointer) noexcept     {         m_allocatorShared.destroy(static_cast<SharedType*>(a_pointer));         m_allocatorShared.deallocate(static_cast<SharedType*>(a_pointer), 1);     }      void destruct() noexcept     {         decltype(m_allocatorControl) l_temp = std::move(m_allocatorControl);         l_temp.m_allocator.destroy(this);         l_temp.m_allocator.deallocate(this, 1);     }      mutable AllocatorTypeControl m_allocatorControl;     mutable AllocatorTypeShared  m_allocatorShared; };  template <template <typename t> class T, typename AllocatorTypeShared, typename SharedType> struct Wrangler {     T<shared_ptr_control_derived<Wrangler, AllocatorTypeShared, SharedType>> m_allocator; };  template <typename SharedType> struct shared_ptr;  template <typename SharedType> struct weak_ptr {     friend struct shared_ptr<SharedType>;      weak_ptr() : m_pointer(nullptr), m_control(nullptr) { }      weak_ptr(const weak_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(const weak_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_weak();         }     }      weak_ptr(weak_ptr<SharedType>&& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(shared_ptr<T>&&)" << std::endl;          a_that.m_pointer = nullptr;         a_that.m_control = nullptr;     }      weak_ptr(const shared_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(const shared_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_weak();         }     }      weak_ptr<SharedType>& operator=(const weak_ptr<SharedType>& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (const weak_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_weak(); }         }          return *this;     }      weak_ptr<SharedType>& operator=(weak_ptr<SharedType>&& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (weak_ptr<T>&&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }         }          m_pointer = a_rhs.m_pointer;         m_control = a_rhs.m_control;         a_rhs.m_pointer = nullptr;         a_rhs.m_control = nullptr;          return *this;     }      weak_ptr<SharedType>& operator=(const shared_ptr<SharedType>& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (const shared_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_weak(); }         }          return *this;     }      ~weak_ptr()     {         if (m_control) { decrement_destruct(); }     }      void decrement_destruct()     {         m_control->decrement_count_weak();          if (m_control->m_weak == 0)         {             if (m_control->m_shared == 0)             {                 std::cout << "weak_ptr -> destructing control block" << std::endl;                  m_control->destruct();             }         }     }      SharedType* operator->() const noexcept { return m_pointer; }      SharedType& operator*() const noexcept { return *m_pointer; }      explicit operator bool() const noexcept { return m_control ? m_control->m_shared : false; }      uint32_t use_count() const noexcept { return m_control ? m_control->m_shared : 0; }      SharedType* get() const noexcept { return m_pointer; };  private:     SharedType* m_pointer;     shared_ptr_control_base* m_control; };  template <typename SharedType> struct friend_struct;  template <typename SharedType> struct shared_ptr {     friend friend_struct<SharedType>;     friend struct weak_ptr<SharedType>;      shared_ptr() : m_pointer(nullptr), m_control(nullptr) { }      shared_ptr(const shared_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "shared_ptr<T>::shared_ptr(const shared_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_shared();         }     }      shared_ptr<SharedType>& operator=(const shared_ptr<SharedType>& a_rhs)     {         std::cout << "shared_ptr<T>& shared_ptr<T>::operator = (const shared_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_shared(); }         }          return *this;     }      ~shared_ptr()     {         if (m_control) { decrement_destruct(); }     }      SharedType* operator->() const noexcept { return m_pointer; }      SharedType& operator*() const noexcept { return *m_pointer; }      explicit operator bool() const noexcept { return m_pointer != nullptr; }      uint32_t use_count() const noexcept { return m_control ? m_control->m_shared : 0; }      void decrement_destruct()     {         m_control->decrement_count_shared();          if (m_control->m_shared == 0)         {             std::cout << "shared_ptr -> destructing shared object" << std::endl;              m_control->destroy_shared(m_pointer);              if (m_control->m_weak == 0) { std::cout << "shared_ptr -> destructing control block" << std::endl; m_control->destruct(); }         }     }      void reset() noexcept { shared_ptr<SharedType>().swap(*this); }      void reset(SharedType* const a_pointer) noexcept { shared_ptr<SharedType>(a_pointer).swap(*this); }      void swap(shared_ptr<SharedType>& a_that) noexcept { std::swap(m_pointer, a_that.m_pointer); std::swap(m_control, a_that.m_control); }      SharedType* get() const noexcept { return m_pointer; };  private:     SharedType* m_pointer;     shared_ptr_control_base* m_control; };  template <typename SharedType> struct friend_struct {     template <typename T>     shared_ptr_control_base*& get_ref_pointer_control(T& a_r_shared_ptr) { return a_r_shared_ptr.m_control; }      template <typename T>     SharedType*& get_ref_pointer_shared(T& a_r_shared_ptr) { return a_r_shared_ptr.m_pointer; } };  template <typename SharedType,           template <typename t> class AllocatorControl = std::allocator,           template <typename t> class AllocatorShared = std::allocator,           typename... Args>  shared_ptr<SharedType> make_shared(Args&&... args) {     using AllocatorControlCreate = Wrangler<AllocatorControl, AllocatorShared<SharedType>, SharedType>;      shared_ptr_control_derived<AllocatorControlCreate, AllocatorShared<SharedType>, SharedType>         l_d(std::move(AllocatorControlCreate()),             std::move(AllocatorShared<SharedType>()));      auto* l_pC = l_d.m_allocatorControl.m_allocator.allocate(1);     SharedType* l_pS = nullptr;      try     {         l_pS = l_d.m_allocatorShared.allocate(1);     }     catch (...)     {         l_d.m_allocatorControl.m_allocator.deallocate(l_pC, 1); throw;     }      try     {         l_d.m_allocatorControl.m_allocator.construct(l_pC, std::move(l_d));     }     catch (...)     {         l_d.m_allocatorControl.m_allocator.deallocate(l_pC, 1); l_d.m_allocatorShared.deallocate(l_pS, 1); throw;     }      try     {         l_pC->m_allocatorShared.construct(l_pS, SharedType(std::forward<Args>(args)...));     }     catch (...)     {         l_pC->m_allocatorControl.m_allocator.destroy(l_pC);         l_pC->m_allocatorControl.m_allocator.deallocate(l_pC, 1); l_pC->m_allocatorShared.deallocate(l_pS, 1); throw;     }      shared_ptr<SharedType> l_s;     friend_struct<SharedType>().get_ref_pointer_control(l_s) = l_pC;     friend_struct<SharedType>().get_ref_pointer_shared(l_s) = l_pS;     return l_s; }  int main() {     auto shared_1 = make_shared<int>(47);     auto shared_2 = shared_1;      {         auto shared_3 = shared_1;          std::cout << shared_1.use_count() << std::endl;     }      shared_2.reset();      weak_ptr<int> weak_1(shared_1);      std::cout << weak_1.use_count() << std::endl;      shared_1.reset();      std::cout << weak_1.use_count() << std::endl;      if (!weak_1)     {         std::cout << "weak_1 is no longer safe to use" << std::endl;     } }   
 

I've made some changes to my code based on suggestions by Loki Astari:

  • Added support for moving allocators into the shared_ptr object by use of a make_shared function
  • Added support for exception safety with try/catch blocks (in the make_shared function)
  • Removed code for instantiating allocators each time a function is called (while I don't use stateful allocators myself, it would be nice to support them if possible)

#include <iostream> #include <memory>  struct shared_ptr_control_base {     virtual ~shared_ptr_control_base() { }      void decrement_count_shared() noexcept { m_shared--; }     void increment_count_shared() noexcept { m_shared++; }      void decrement_count_weak() noexcept { m_weak--; }     void increment_count_weak() noexcept { m_weak++; }      virtual void destroy_shared(void*) noexcept = 0;     virtual void destruct()            noexcept = 0;      uint32_t m_shared = 1;     uint32_t m_weak   = 0; };  template <typename AllocatorTypeControl, typename AllocatorTypeShared, typename SharedType> struct shared_ptr_control_derived : shared_ptr_control_base {     shared_ptr_control_derived() = delete;     shared_ptr_control_derived(const shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&) = delete;      shared_ptr_control_derived(shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&& a_that) :         m_allocatorControl(std::move(a_that.m_allocatorControl)),         m_allocatorShared(std::move(a_that.m_allocatorShared))     {      }      shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&         operator = (const shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&) = delete;     shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&         operator = (shared_ptr_control_derived<AllocatorTypeControl, AllocatorTypeShared, SharedType>&&) = delete;      shared_ptr_control_derived(AllocatorTypeControl&& a_allocatorC,                                AllocatorTypeShared&& a_allocatorS) :         m_allocatorControl(a_allocatorC),         m_allocatorShared(a_allocatorS)     {      }      void destroy_shared(void* a_pointer) noexcept     {         m_allocatorShared.destroy(static_cast<SharedType*>(a_pointer));         m_allocatorShared.deallocate(static_cast<SharedType*>(a_pointer), 1);     }      void destruct() noexcept     {         decltype(m_allocatorControl) l_temp = std::move(m_allocatorControl);         l_temp.m_allocator.destroy(this);         l_temp.m_allocator.deallocate(this, 1);     }      mutable AllocatorTypeControl m_allocatorControl;     mutable AllocatorTypeShared  m_allocatorShared; };  template <template <typename t> class T, typename AllocatorTypeShared, typename SharedType> struct Wrangler {     T<shared_ptr_control_derived<Wrangler, AllocatorTypeShared, SharedType>> m_allocator; };  template <typename SharedType> struct shared_ptr;  template <typename SharedType> struct weak_ptr {     friend struct shared_ptr<SharedType>;      weak_ptr() : m_pointer(nullptr), m_control(nullptr) { }      weak_ptr(const weak_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(const weak_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_weak();         }     }      weak_ptr(weak_ptr<SharedType>&& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(shared_ptr<T>&&)" << std::endl;          a_that.m_pointer = nullptr;         a_that.m_control = nullptr;     }      weak_ptr(const shared_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "weak_ptr<T>::weak_ptr(const shared_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_weak();         }     }      weak_ptr<SharedType>& operator=(const weak_ptr<SharedType>& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (const weak_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_weak(); }         }          return *this;     }      weak_ptr<SharedType>& operator=(weak_ptr<SharedType>&& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (weak_ptr<T>&&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }         }          m_pointer = a_rhs.m_pointer;         m_control = a_rhs.m_control;         a_rhs.m_pointer = nullptr;         a_rhs.m_control = nullptr;          return *this;     }      weak_ptr<SharedType>& operator=(const shared_ptr<SharedType>& a_rhs)     {         std::cout << "weak_ptr<T>& weak_ptr<T>::operator = (const shared_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_weak(); }         }          return *this;     }      ~weak_ptr()     {         if (m_control) { decrement_destruct(); }     }      void decrement_destruct()     {         m_control->decrement_count_weak();          if (m_control->m_weak == 0)         {             if (m_control->m_shared == 0)             {                 std::cout << "weak_ptr -> destructing control block" << std::endl;                  m_control->destruct();             }         }     }      SharedType* operator->() const noexcept { return m_pointer; }      SharedType& operator*() const noexcept { return *m_pointer; }      explicit operator bool() const noexcept { return m_control ? m_control->m_shared : false; }      uint32_t use_count() const noexcept { return m_control ? m_control->m_shared : 0; }      SharedType* get() const noexcept { return m_pointer; };  private:     SharedType* m_pointer;     shared_ptr_control_base* m_control; };  template <typename SharedType> struct friend_struct;  template <typename SharedType> struct shared_ptr {     friend friend_struct<SharedType>;     friend struct weak_ptr<SharedType>;      shared_ptr() : m_pointer(nullptr), m_control(nullptr) { }      shared_ptr(const shared_ptr<SharedType>& a_that) :         m_pointer(a_that.m_pointer),         m_control(a_that.m_control)     {         std::cout << "shared_ptr<T>::shared_ptr(const shared_ptr<T>&)" << std::endl;          if (m_control != nullptr)         {             m_control->increment_count_shared();         }     }      shared_ptr<SharedType>& operator=(const shared_ptr<SharedType>& a_rhs)     {         std::cout << "shared_ptr<T>& shared_ptr<T>::operator = (const shared_ptr<T>&)" << std::endl;          if (a_rhs.m_control != m_control)         {             if (m_control != nullptr) { decrement_destruct(); }              m_pointer = a_rhs.m_pointer;             m_control = a_rhs.m_control;              if (m_control != nullptr) { m_control->increment_count_shared(); }         }          return *this;     }      ~shared_ptr()     {         if (m_control) { decrement_destruct(); }     }      SharedType* operator->() const noexcept { return m_pointer; }      SharedType& operator*() const noexcept { return *m_pointer; }      explicit operator bool() const noexcept { return m_pointer != nullptr; }      uint32_t use_count() const noexcept { return m_control ? m_control->m_shared : 0; }      void decrement_destruct()     {         m_control->decrement_count_shared();          if (m_control->m_shared == 0)         {             std::cout << "shared_ptr -> destructing shared object" << std::endl;              m_control->destroy_shared(m_pointer);              if (m_control->m_weak == 0) { std::cout << "shared_ptr -> destructing control block" << std::endl; m_control->destruct(); }         }     }      void reset() noexcept { shared_ptr<SharedType>().swap(*this); }      void reset(SharedType* const a_pointer) noexcept { shared_ptr<SharedType>(a_pointer).swap(*this); }      void swap(shared_ptr<SharedType>& a_that) noexcept { std::swap(m_pointer, a_that.m_pointer); std::swap(m_control, a_that.m_control); }      SharedType* get() const noexcept { return m_pointer; };  private:     SharedType* m_pointer;     shared_ptr_control_base* m_control; };  template <typename SharedType> struct friend_struct {     template <typename T>     shared_ptr_control_base*& get_ref_pointer_control(T& a_r_shared_ptr) { return a_r_shared_ptr.m_control; }      template <typename T>     SharedType*& get_ref_pointer_shared(T& a_r_shared_ptr) { return a_r_shared_ptr.m_pointer; } };  template <typename SharedType,           template <typename t> class AllocatorControl = std::allocator,           template <typename t> class AllocatorShared = std::allocator,           typename... Args>  shared_ptr<SharedType> make_shared(Args&&... args) {     using AllocatorControlCreate = Wrangler<AllocatorControl, AllocatorShared<SharedType>, SharedType>;      shared_ptr_control_derived<AllocatorControlCreate, AllocatorShared<SharedType>, SharedType>         l_d(std::move(AllocatorControlCreate()),             std::move(AllocatorShared<SharedType>()));      auto* l_pC = l_d.m_allocatorControl.m_allocator.allocate(1);     SharedType* l_pS = nullptr;      try     {         l_pS = l_d.m_allocatorShared.allocate(1);     }     catch (...)     {         l_d.m_allocatorControl.m_allocator.deallocate(l_pC, 1); throw;     }      try     {         l_d.m_allocatorControl.m_allocator.construct(l_pC, std::move(l_d));     }     catch (...)     {         l_d.m_allocatorControl.m_allocator.deallocate(l_pC, 1); l_d.m_allocatorShared.deallocate(l_pS, 1); throw;     }      try     {         l_pC->m_allocatorShared.construct(l_pS, SharedType(std::forward<Args>(args)...));     }     catch (...)     {         l_pC->m_allocatorControl.m_allocator.destroy(l_pC);         l_pC->m_allocatorControl.m_allocator.deallocate(l_pC, 1); l_pC->m_allocatorShared.deallocate(l_pS, 1); throw;     }      shared_ptr<SharedType> l_s;     friend_struct<SharedType>().get_ref_pointer_control(l_s) = l_pC;     friend_struct<SharedType>().get_ref_pointer_shared(l_s) = l_pS;     return l_s; }  int main() {     auto shared_1 = make_shared<int>(47);     auto shared_2 = shared_1;      {         auto shared_3 = shared_1;          std::cout << shared_1.use_count() << std::endl;     }      shared_2.reset();      weak_ptr<int> weak_1(shared_1);      std::cout << weak_1.use_count() << std::endl;      shared_1.reset();      std::cout << weak_1.use_count() << std::endl;      if (!weak_1)     {         std::cout << "weak_1 is no longer safe to use" << std::endl;     } } 
 
 
   
   

Relacionados problema

10  Clase personalizada para un ido prestado_ptr <t>?  ( Custom class for a borrowed unique ptrt ) 
En C ++ 11, tiendo a tener objetos maestros que mantienen la propiedad única de una colección de algunos objetos para niños. Asumamos que estos objetos para n...

6  Implementando un árbol binario en C ++ usando "Std :: ique_ptr"  ( Implementing a binary tree in c using stdunique ptr ) 
He implementado una clase de árbol de búsqueda binaria simple en C ++ usando Dim Wb1 As Workbook, Wb2 As Workbook Dim Wk4 As Worksheet, Wk5 As Wor...

1  Pasando objetos atómicamente a través de hilos sin cerraduras o carreras de datos para la sincronización de audio  ( Passing objects atomically across threads without locks or data races for audio ) 
Estoy aprendiendo sobre una de las partes más difíciles del desarrollo de audio: la sincronización entre el hilo de audio y el hilo GUI. Por la discusión aquí...

7  Encontrando la primera carta recurrente en cada cadena de un conjunto dado  ( Finding first recurring letter in each string of a given set ) 
La primera entrada es el número de cadenas ex: 5 La segunda entrada es un conjunto de cuerdas ex: Hola mundo ¿Cómo estás Salga de la letra en la cadena EX:...

7  Pase los datos del puntero a través de múltiples funciones  ( Pass pointer data across multiple functions ) 
Me gustaría revisar en el siguiente proceso de asignación de memoria dinámica y sugerencias sobre si hay alguna fugas de memoria. El siguiente código no es un...

4  (C ++ 14) Estado de manejo en la función C-Style Pointer Callbacks  ( C14 handling state in c style function pointer callbacks ) 
Tengo algunos problemas que se presentan con una solución sensible para usar el estado compartido en un puntero de función de estilo C. Estoy usando GLFW para...

19  Scoped_PTR para C ++ / CLI (asegúrese de que el objeto administrado libera correctamente el objeto nativo de propiedad)  ( Scoped ptr for c cli ensure managed object properly frees owned native object ) 
Motivar así: ¿Hay un C ++ / Proyecto CLI Smart Pointer (por ejemplo, scoped_ptr)? Estoy interesado en cualquier comentario crítico, y especialmente identi...

4  Creando una lista con una estructura en C  ( Creating a list using a struct in c ) 
Acabo de entrar en struct S y yo decidimos crear una lista usándolos: #include<stdio.h> #include<stdlib.h> int main(void) { char counter; struct...

3  Funciones de manipulación de comando para un programa de concha de juguete  ( Command manipulation functions for a toy shell program ) 
Estoy escribiendo un pequeño programa que se supone que actúa como una concha de algún tipo. Funciona de unas pocas estructuras básicas, una de ellas es un 9...

4  Generar todas las permutaciones en c  ( Generate all permutations in c ) 
He escrito código para generar todas las permutaciones en C como se explica aquí . ¿Cómo se puede optimizar el código? ¿Hay alguna fugas de memoria? int f...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos