开发者

Can you mix shared pointers with non-pointer data members?

开发者 https://www.devze.com 2023-01-29 10:11 出处:网络
Take the following example: class BookManager { ... }; class Book { public: void setBookManager(BookManager *bookManager) {m_bookManager = bookManager;}

Take the following example:

class BookManager
   {
   ...
   };

class Book
   {
   public:
      void setBookManager(BookManager *bookManager) {m_bookManager = bookManager;}
   private:
      BookManager *m_bookManager;
   };

Since the caller is typically not interested in keeping a BookManager for a Book if the Book is deleted, and since multiple Books can share a BookManager, I make the pointer to BookManager, a shared pointer, like this:

typedef std::shared_ptr<BookManager> BookManagerPtr;

class Book
   {
   public:
      void setBookManager(BookManagerPtr bookManager) {m_bookManager = bookManager;}
   private:
      BookManagerPtr m_bookManager;
   };

Problem is that a module in my application has its own BookManager that it wants to give to each of its books, like this:

class MyModule
   {
   public:
      Book *createBook()
         {
         Book *newBook = new Book();
         newBook->setBookManager(BookManagerPtr(&m_bookManager));
         }
   private:
      BookManager m_bookManager;
   };

Of course this doesn't work because the last deleted book will also delete the BookManager instance, which it shouldn't delete because it's a normal data member of MyModule.

This means that MyModule should also use a shared pointer to BookManager, like this:

class MyModule
   {
   开发者_开发问答public:
      MyModule()
      : m_bookManager(new BookManager())
         {
         }
      Book *createBook()
         {
         Book *newBook = new Book();
         newBook->setBookManager(m_bookManager);
         }
   private:
      BookManagerPtr m_bookManager;
   };

Is this the only way to solve this? Or is there a way to still have normal data members and use shared pointers to it (e.g. by initializing its reference count to 1)?


create a copy BookManagerPtr(new BookMarkManager(m_bookManager)), make m_bookManager a BookManagerPtr too or make book a template thus allowing it to use BookManager* and shared_ptr. shared_ptr is about shared ownership, in your example MyModule owns the example and book don't, so it's not compatible with shared_ptr


What about using custom deleter which does nothing?


I know you've accepted an answer, but another approach (if you have boost) could be to use references. By default you can't have a reference member in the Book class, however if you wrap it in an optional i.e. boost::optional<BookManager&> then you can have a reference, next, in the setBookManager method, pass in the reference (or const reference) and assign this to the optional. To use, deref as you would a smart pointer...


The safe way to model non-ownership is with a weak_ptr this way the lifetime is still controlled by MyModule while still having Book reference a BookManager and know if the BookManager it references is still valid.

0

精彩评论

暂无评论...
验证码 换一张
取 消