资源薄弱和工厂设计模式

时间:2012-01-19 12:26:29

标签: c++ design-patterns smart-pointers

考虑如何最好地处理以下设计(伪C ++代码)的方法:

class Display {

  public:

   Bitmap GetBitmap(uint16 width, uint16 height);

  private:

   // A list of active bitmaps
   std::set<Bitmap> bitmaps;
}

...其中Display是Bitmap对象的工厂(和唯一所有者)。显示器还必须跟踪std::set容器中所有已分配的位图,并可以随时选择使其无效(如全屏切换)。

所以基本上Bitmap是一个弱资源句柄,持有句柄的人必须在使用它之前检查它是否有效。

我现在的理论解决方案是使用C ++智能指针:

  • GetBitmap()将返回weak_ptr<Bitmap>,因此可以使用weakBitmap.lock()检查其有效性。
  • 内部位图std :: set容器将保留shared_ptr<Bitmap>,以便能够提供弱位图指针。

实施指定设计的最佳方法是什么?是否存在我缺少的给定功能的事实上的设计模式?

1 个答案:

答案 0 :(得分:2)

我认为您可能需要考虑扭转局面:放弃您创建的对象的所有权(例如,返回boost::shared_ptr<Bitmap>)并仅保留内部集合中对象的弱指针(例如std::list<boost::weak_ptr<Bitmap>> )。每当用户要求使用Bitmap时,请对您的集合执行锁定并在其中添加新的Bitmap。如果你的集合是一个列表,你可以安全地将迭代器存储到刚刚添加的元素中,然后将其从集合中删除,从而处理销毁Bitmap。

由于boost::shared_ptr::lock是原子的,因此在多线程时它也可以工作。但是你仍然需要通过锁来保护对集合的访问。

以下是示例代码:

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>

class Display;

class Bitmap : boost::noncopyable
{
  friend class Display;
  Bitmap(int, Display* d) : display(d)
  {}

  Display* display;
public:

  ~Bitmap(); // see below for definition
};

typedef boost::shared_ptr<Bitmap> BitmapPtr;

class Display
{
  typedef std::list<boost::weak_ptr<Bitmap>> bitmaps_t;
  typedef std::map<Bitmap*, bitmaps_t::iterator> bitmap_map_t;
  bitmaps_t     bitmaps_;
  bitmap_map_t  bitmap_map_;
  boost::mutex  mutex_;

  friend class Bitmap;
  void Remove(Bitmap* p)
  {
    boost::lock_guard<boost::mutex> g(mutex_);
    bitmap_map_t::iterator i = bitmap_map_.find(p);
    if (i != bitmap_map_.end())
    {
      bitmaps_.erase(i->second);
      bitmap_map_.erase(i);
    }
  }

public:
  ~Display()
  {
    boost::lock_guard<boost::mutex> g(mutex_);
    for (bitmaps_t::iterator i = bitmaps_.begin(); i != bitmaps_.end(); ++i)
    {
      BitmapPtr ptr = i->lock();
      if (ptr)
        ptr->display = NULL;
    }
  }

  BitmapPtr GetBitmap(int i)
  {
    BitmapPtr r(new Bitmap(i, this));
    boost::lock_guard<boost::mutex> g(mutex_);
    bitmaps_.push_back(boost::weak_ptr<Bitmap>(r));
    bitmap_map_[r.get()] = --bitmaps_.end();
    return r;
  }
};

Bitmap::~Bitmap()
{
  if (display)
    display->Remove(this);
}

请注意BitmapDisplay之间存在双向链接 - 它们彼此保持一个弱指针,这意味着它们可以自由地进行通信。例如,如果您希望Display能够“销毁”Bitmaps,它可以通过将“display”更新为NULL来禁用它们,如Display析构函数中所示。 Display每次想要访问Bitmap(析构函数中的示例)时都必须锁定weak_ptr<Bitmap>,但如果这种通信不经常发生,这不应该是一个很大的问题。

对于线程安全,您可能需要在每次要“禁用”它时锁定Bitmap,即将显示成员重置为NULL,并在每次要从Bitmap访问“display”时将其锁定。由于这会影响性能,因此您可能希望在位图中将Display*替换为weak_ptr<Display>。这也消除了对Display中析构函数的需求。这是更新的代码:

class Bitmap : boost::noncopyable
{
  friend class Display;
  Bitmap(int, const boost::shared_ptr<Display>& d) : display(d)
  {}

  boost::weak_ptr<Display> display;

public:
  ~Bitmap(); // see below for definition
};

typedef boost::shared_ptr<Bitmap> BitmapPtr;

class Display : public boost::enable_shared_from_this<Display>
              , boost::noncopyable
{
  //... no change here

public:
  BitmapPtr GetBitmap(int i)
  {
    BitmapPtr r(new Bitmap(i, shared_from_this()));
    boost::lock_guard<boost::mutex> g(mutex_);
    bitmaps_.push_back(boost::weak_ptr<Bitmap>(r));
    bitmap_map_[r.get()] = --bitmaps_.end();
    return r;
  }
};

Bitmap::~Bitmap()
{
  boost::shared_ptr<Display> d(display);
  if (d)
    d->Remove(this);
}

在这种情况下,Bitmap中的“禁用”显示指针是线程安全的,没有显式同步,如下所示:

Display::DisableBitmap(bitmaps_t::iterator i)
{
  BitmapPtr ptr = i->lock();
  if (ptr)
    ptr->display.reset();
}