Search code examples
c++ooppointersc++11weak-ptr

c++ classes linked to each other with std safe pointers (c++)


I have problem in my project. I believe shared/weak pointers from new c++ stabdards can solve it but its unclear to me how. In book i read about standard library there is no comment on my idea how to use these pointers.

In my application i have Library class. This class has internal vector of Book objects. These objects usually created inside Library class, though external code queries Books objects from it using functions and uses them later. Each Book instance has a public pointer to 'host' Library instance.

Sometimes external code deletes Library and creates new, but it may still use previously queried Book objects from old library. My problem is that Book class should drop pointer that no longer valid, so book will not contain invalid pointer to deleted library instance.

It is unclear for me how to implement weak pointers to book class to achieve such behavior.


Solution

  • It is possible.

    As the Library needs to know how to add a book, it needs to know how to get a weak_ptr to itself. Luckily there is a helper base class called enable_shared_from_this which allows you to do that.

    #include <memory>
    #include <iostream>
    #include <vector>
    
    class Library;
    
    struct Book {
      std::weak_ptr<Library> host_library;
    };
    
    class Library : public std::enable_shared_from_this<Library> {
        std::vector<Book> books;
     public:
      const Book& getBook(size_t index) const { return books.at(index); }
      void addBook() { 
          books.emplace_back();
          books.back().host_library = shared_from_this();
      }
    };
    
    int main() {
        auto library = std::make_shared<Library>();
        library->addBook();
    
        auto book_copy = library->getBook(0);              
        library.reset();                                   // Destroy the library
    
        auto old_library = book_copy.host_library.lock();  // Try to get a shared_ptr
        if (!old_library)                                  // to the library from the book.
            std::cout << "Library gone!\n";
    }
    

    Live demo.

    For it to work, Library always needs to be created as a shared_ptr. You could enforce that by making the constructor private and having a static create function that returns a shared_ptr.