I have a question about the behaviour of shared_ptr.reset().
In this scenario I have a cyclic reference with the following classes. I have a book and an owner, which both have std::shared_ptrs to each other, creating a cyclic reference.
Book.h
#pragma once
class Owner;
class Book
{
public:
Book(std::string title);
~Book();
void OutputDetails();
void SetOwner(std::shared_ptr<Owner> owner);
void OutputOwnerInformation();
private:
std::string m_title;
std::shared_ptr<Owner> m_owner; // Book hangs onto the owner and creates a circular dependency
};
Book.cpp
#include "stdafx.h"
#include <iostream>
#include "Book.h"
#include "Owner.h"
Book::Book(std::string title) : m_title(title) {}
Book::~Book() {
std::cout << "Book Destroyed" << std::endl;
}
void Book::SetOwner(std::shared_ptr<Owner> owner) {
m_owner = owner; // strong reference
}
void Book::OutputOwnerInformation() {
std::cout << "Owner is: " << m_owner->GetName() << std::endl;
}
void Book::OutputOwnerInformation() {
std::cout << "Owner is: " << m_owner->GetName() << std::endl;
}
Owner.h
#pragma once
class Book; // To avoid circular #includes
class Owner
{
public:
Owner(std::string name, std::shared_ptr<Book> book);
~Owner();
void OutputDetails();
std::string GetName();
private:
std::string m_name;
std::shared_ptr<Book> m_book; // Owner hangs onto the book
};
Owner.cpp
#include "stdafx.h"
#include "Owner.h"
#include "Book.h"
Owner::Owner(std::string name, std::shared_ptr<Book> book) : m_name(name), m_book(book) {}
Owner::~Owner() {
std::cout << "Owner Destroyed" << std::endl;
}
void Owner::OutputDetails() {
std::cout << m_name << " owns " << std::endl;
m_book->OutputDetails();
}
std::string Owner::GetName() {
return m_name;
}
Here is the main.cpp. In this case, book and owner have strong references to each other and will memory leak once _tmain exits its scope. The destructors for both book and owner are not called when I insert breakpoints in the respective destructors.
main.cpp
#include "stdafx.h"
#include <memory>
#include "Book.h"
#include "Owner.h"
int _tmain(int, _TCHAR*)
{
{
std::shared_ptr<Book> book = std::shared_ptr<Book>(new Book("Moby Dick"));
std::shared_ptr<Owner> owner = std::shared_ptr<Owner>(new Owner("George Heriot", book));
// Introduced a circular dependency so
// neither gets deleted
book->SetOwner(owner);
owner->OutputDetails();
book->OutputOwnerInformation();
}
return 0;
}
I wanted to see if I could reset() the pointers such that the destructor was called and to break the cyclic dependency. According to my understanding of shared_ptr.reset(), the object should become empty.
http://www.cplusplus.com/reference/memory/shared_ptr/reset/
However, my break points in both destructors are not being hit. My assumption would be that because I have reset both book and owner, the reference count would drop to 0 for both and they would be destroyed when _tmain returns.
main2.cpp
#include "stdafx.h"
#include <memory>
#include "Book.h"
#include "Owner.h"
int _tmain(int, _TCHAR*)
{
{
std::shared_ptr<Book> book = std::shared_ptr<Book>(new Book("Moby Dick"));
std::shared_ptr<Owner> owner = std::shared_ptr<Owner>(new Owner("George Heriot", book));
// Introduced a circular dependency so
// neither gets deleted
book->SetOwner(owner);
owner->OutputDetails();
book->OutputOwnerInformation();
owner.reset();
book.reset();
}
return 0;
}
I understand that this is already horrible code and I could use a weak_ptr to remove the cyclic dependency but I am just curious why reset() does not break this dependency.