RAII objects in a singleton container?

235 views Asked by At

So, I was wondering how to create some kind of a code audit in C++ using a tracking mechanism of sorts.

Consider the following classes, where two separate mirrors, A and B, provide messages to a listener.

class MirrorA
{
  void one(int a) {  m_mirrrorListener.three(a); }
};

class MirrorB
{
  void two(int b) {  m_mirrrorListener.three(b); }
};

class MirrorListener
{
  void three(int c) { std::cout << c << std::endl; }
};

Now, let's say that, for some reason, three needs to know if it was triggered by one() or two().

We can pass along a value like so:

enum mirrorSource_t
{
  FROM_ONE = 1,
  FROM_TWO = 2
}

class MirrorA
{
  void one(int a) {  m_mirrrorListener.three(a, FROM_ONE); }
};

class MirrorB
{
  void two(int b) {  m_mirrrorListener.three(b, FROM_TWO); }
};

class MirrorListener
{
  void three(int c, mirrorSource_t source) { std::cout << c << " From " << source << std::endl; }
};

But then we have to update the signature of three and its invocation whenever it needs new information.

So, what if we had a singleton message tracker (referenced as m_mirrorMessageTracker in other classes) that could track an arbitrary number of messages?

enum mirrorSource_t
{
  FROM_ONE = 1,
  FROM_TWO = 2
}

class MirrorMessage
{
  public:
    MirrorMessage(mirrrorSource_t t) :  source(t)  {}
    get() { return source; }

  private:
    mirrorSource_t  source;
};

class MirrorMessageTracker {
public:

  MirrorMessage& MirrorMessageTracker::trackEvent(mirrorSource_t value)
  {
    trackedMessages.push_back(MirrorMessage(value));
    return trackedMessages.back();
  }

  MirrorMessage&  MirrorMesssageTracker::getCurrentEvent()
  {
    return trackedMessages.back();
  }

  static MirrorMessageTracker& getInstance()
  { 
    if(!m_Tracker)
    {
       m_pTracker = new MirrorMessageTracker();
    }
    return *m_pTracker; 
  }

private:
    MirrorMessageTracker() { }; //  
    static MirrorMessageTracker* m_pTracker;
    std::vector<MirrorMessage> trackedMessages;  // assumption is that tracked messages are
                                                 // single-threaded and unwind in a LIFO manner.
};

class MirrorA
{
  void one(int a)
  {
    MirrorMessage createdMessage = m_MirrorMessageTracker.trackMessage(FROM_ONE);
    m_mirrrorListener.three(a);
  }
};

class MirrorB
{
  void two(int b)
  {
    MirrorMessage createdMessage = m_MirrorMessageTracker.trackMessage(FROM_TWO);
    m_mirrrorListener.three(b);
  }
};

class MirrorListener
{
  void three(int c) 
  {
    MirrorMessage& message = m_MirrorMessageTracker.getCurrentMessage();
    if (message.get() == FROM_ONE)
    {
      std::cout << c << std::endl;
    }
    else if (message.get() == FROM_TWO)
    {
      std::cout << c << c << std::endl;
    }
    else
    {
      std::cout << c << c << c << std::endl;
    }
  }
};

I would like for the tracked message to be removed from the tracker after createdMessage goes out of scope in one and two. Can this be done with a particular type of boost smart pointer? Something like:

  std::vector<boost::shared_ptr<MirrorMessage> > trackedMessages;

vector::push_back would create a copy of the message and place it into the vector so I'm not sure if it's possible with a shared pointer, though.

1

There are 1 answers

3
πάντα ῥεῖ On

The more common pattern to create singletons actually is

  static MirrorMessageTracker& getInstance() { 
      static MirrorMessageTracker theMirrorMesageTracker;
      return theMirrorMesageTracker; 
  }

Also you should consider to forbid copying and assignment for your MirrorMessageTracker class, by making these operations private:

  private:
      MirrorMessageTracker() { };
      MirrorMessageTracker(const MirrorMessageTracker&); // <<<
      MirrorMessageTracker& operator=(const MirrorMessageTracker&); // <<<