LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-22-2021, 03:34 AM   #1
shamjs
Member
 
Registered: Sep 2011
Posts: 93

Rep: Reputation: Disabled
cyclic dependency of shared ptr, not allowing destructor to invoke


In my code looks like I have a cyclic dependency of shared pointer as a result of it I believe destructor is not getting invoked.

Here is my code

Code:
#include<stdio.h>
#include<iostream>
#include<memory>
#include<list>

using namespace std;

class IObserver {
 public:
  IObserver() {}	 
  virtual ~IObserver();
  virtual void Update(const std::string &message_from_subject) = 0;
  virtual int GetObjectId() = 0;
};

class ISubject {
 public:
  ISubject() {}	 
  virtual ~ISubject();
  virtual void Attach(shared_ptr<IObserver> pObserver) = 0; 
  virtual void Detach(shared_ptr<IObserver> pObserver) = 0; 
  virtual void Notify() = 0;
};

class Subject : public ISubject {
  public:
  Subject() { cout<<"Subject constructor"<<endl; }	  
    ~Subject() {
    std::cout << "Subject Destructor.\n";
  }
 
  void Attach(shared_ptr<IObserver> pObserver); 
  void Detach(shared_ptr<IObserver> pObserver);
  void Notify(); 
  void CreateMessage(std::string message);

  private:
  typedef shared_ptr<IObserver> PtrObserver;
  std::list<PtrObserver> plist_observer;
  std::string message;
};

class Observer : public IObserver {
 public:
  Observer(shared_ptr<Subject> pSubject);
    ~Observer() {
    std::cout << "Observer Destructor Id " <<objId<<endl; 
  }

  void Update(const std::string &message_from_subject);
  void DeleteFromList();
  int GetObjectId();

 private:
  std::string message_from_subject_;
  shared_ptr<Subject> ptrSubject;
  int objId;
  static int objCount;
 };

#include "ObserverPattern.hpp"

int Observer::objCount = 0;

IObserver::~IObserver() {
 cout<<"Done with IObserver"<<endl;
}


ISubject::~ISubject() {
 cout<<"Done with ISubject"<<endl;
 	
}	

/* Subject::Attach
 * Description : Attach/subscribe the interested obersever
 * param : pObserver 
 */ 
void Subject::Attach(shared_ptr<IObserver> pObserver) {
 cout<<"Subject::Attach attaching Object"<<pObserver->GetObjectId()<<endl;	 
 plist_observer.push_back(pObserver);
}

/* Subject::Attach
 * Description : Detach/unsubscribe  the interested obersever
 * param : pObserver
 * */

void Subject::Detach(shared_ptr<IObserver> pObserver) {
 cout<<"Subject::Detach detaching Object"<<pObserver->GetObjectId()<<endl;	
 plist_observer.remove(pObserver);
}

/* Subject::Notify
 * Description : Notify the subscribed observers about the message
 * */
void Subject::Notify() {
    cout<<"Subject::Notify"<<endl;	
    std::list<PtrObserver>::iterator iterator = plist_observer.begin();
    
    while (iterator != plist_observer.end()) {
      (*iterator)->Update(message);
      ++iterator;
    }
}

/* Subject::CreateMessage
 * Description : Create a message and notify the same for all the interested observers
 * */
void Subject::CreateMessage(std::string message) { 
 cout<<"######### Subject::CreateMessage ########## "<<message<<endl;
 this->message = message;
 Notify();
}

Observer::Observer(shared_ptr<Subject> pSubject) : ptrSubject(pSubject) {
 objCount++;
 objId = objCount;
 cout<<" Constructing Object "<<objId<<endl;
 ptrSubject->Attach(make_shared<Observer>(*this));
}


/* Observer::GetObjectId
 * Description : Return the object Id associated with the object.
 */
int Observer::GetObjectId() {
  return objId;
}

/* Observer::Update
 * Description : Receives the updates from the subject
 */ 
void Observer::Update(const std::string &message_from_subject) {
    message_from_subject_ = message_from_subject;
    cout<<"Object Id "<<objId<<" Received "<<message_from_subject_<<" message"<<endl;
  }

/* Observer::DeleteFromList
 * Description : 
 * */
void Observer::DeleteFromList() {
  shared_ptr<IObserver> observer(this);	
  ptrSubject->Detach((observer));
}


int main() {

 shared_ptr<Subject> subject = make_shared<Subject>();
 
 shared_ptr<Observer> observer1(make_shared<Observer>(subject));
 shared_ptr<Observer> observer2(make_shared<Observer>(subject));
 shared_ptr<Observer> observer3(make_shared<Observer>(subject));


 subject->CreateMessage("Hi Hello");
 
 //observer2->DeleteFromList(); // Double free or corruption error
 subject->Detach(observer2); // does not detach observer2
 
 shared_ptr<Observer> observer4(make_shared<Observer>(subject));

 subject->CreateMessage("Welcome");


 return 0;
}
Here is the output

Code:
Subject constructor
 Constructing Object 1
Subject::Attach attaching Object1
 Constructing Object 2
Subject::Attach attaching Object2
 Constructing Object 3
Subject::Attach attaching Object3
######### Subject::CreateMessage ########## Hi Hello
Subject::Notify
Object Id 1 Received Hi Hello message
Object Id 2 Received Hi Hello message
Object Id 3 Received Hi Hello message
Subject::Detach detaching Object2
 Constructing Object 4
Subject::Attach attaching Object4
######### Subject::CreateMessage ########## Welcome
Subject::Notify
Object Id 1 Received Welcome message
Object Id 2 Received Welcome message
Object Id 3 Received Welcome message
Object Id 4 Received Welcome message
Observer Destructor Id 4
Done with IObserver
Observer Destructor Id 3
Done with IObserver
Observer Destructor Id 2
Done with IObserver
Observer Destructor Id 1
Done with IObserver
Subject class contains a list of IObserver shared pointers
Observer class has a shared pointer referring to Subject.

Issues
1. Destructor of Subject and ISubject class is not invoked
2. observer2->DeleteFromList(); // Double free or corruption error is noticed
3. subject->Detach(observer2); // is not detaching the observer2

I need inputs on
1. how to resolve this cyclic dependency error of the shared ptr
2. And why I am unable to detach observer2 from the list

Inputs will be appreciated.
 
Old 07-23-2021, 02:06 PM   #2
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,263
Blog Entries: 24

Rep: Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194Reputation: 4194
As no one else has stepped in...

Frankly, that is just more code than I have time or interest to try to digest. I would suggest that you continue the path you are on to try to understand how you code is actually working and why that differs from your expectations.

You seem to be asking the right questions, so the next step in troubleshooting is to work up a simplest example which will unambiguously demonstrate why it is working as it is - which is your answer. If you cannot then answer the question being explored you will at least have minimal example to post so that others can more quickly understand the problem and offer suggestions.

You may also want to review the Site FAQ for guidance in asking well formed questions. Especially visit the link from that page, How to Ask Questions the Smart Way for discussion of things to consider when asking others for help. The better you understand your problem, the better you can explain it to others!

Good luck!
 
Old 07-23-2021, 09:29 PM   #3
dugan
LQ Guru
 
Registered: Nov 2003
Location: Canada
Distribution: distro hopper
Posts: 11,224

Rep: Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320Reputation: 5320
The cyclic dependency is easy to solve. An Observer should just not have any sort of link back to its Subject. Let's start there.

If you really need it (you don't), you can change that shared_ptr to a weak_ptr, as suggested here:

https://stackoverflow.com/a/51806930/240515

Last edited by dugan; 07-23-2021 at 11:21 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Struct pointer *ptr = *ptr ? errigour Programming 11 02-13-2014 03:39 AM
[SOLVED] container_of:why not "const typeof(*ptr) *__mptr=(ptr);" songcaidao Linux - Kernel 6 10-26-2013 08:35 AM
[SOLVED] Pointer arithmetic question : *ptr++ or (*ptr)++ theKbStockpiler Programming 8 06-02-2010 11:12 AM
Cyclic dependency when using extern symbols from libraries Learnit Programming 3 05-06-2010 07:26 PM
ndiswrapper-utils & ndiswrapper-modules cyclic dependency benoit808 Debian 4 02-19-2007 05:35 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:08 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration