资源和工厂设计模式薄弱

Weak resources and factory design pattern

本文关键字:设计模式 工厂 资源      更新时间:2023-10-16

想出一种如何最好地处理以下设计(伪C++代码(的方法:

class Display {
  public:
   Bitmap GetBitmap(uint16 width, uint16 height);
  private:
   // A list of active bitmaps
   std::set<Bitmap> bitmaps;
}

。其中 Display 是位图对象的工厂(和唯一所有者(。Display 还必须跟踪std::set容器内所有分配的位图,并可能随时选择使其失效/删除(例如在全屏切换中(。

因此,从本质上讲,位图是一个弱资源句柄,无论谁持有该句柄,都必须在使用它之前检查它是否有效。

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

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

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

我认为您可能需要考虑扭转局面:放弃您创建的对象的所有权(例如返回boost::shared_ptr<Bitmap>(,只保留指向内部集合中对象的弱指针(例如 std::list<boost::weak_ptr<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 能够"销毁"位图,则只需通过将"display"更新为 NULL 来禁用它们,如析构函数Display所示。 Display每次想要访问位图(析构函数中的示例(时都必须锁定weak_ptr<Bitmap>,但如果这种通信不经常发生,这应该不是什么大问题。

为了线程安全,您可能需要在每次想要"禁用"位图时锁定它,即将显示成员重置为 NULL,并在每次要从位图访问"显示"时锁定它。由于这会对性能产生影响,因此您可能希望在 Bitmap 中将Display*替换为weak_ptr<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);
}
在这种情况下,在

位图中"禁用"显示指针是线程安全的,无需显式同步,如下所示:

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