使用享元模式在位图对象之间共享位图

4

大家好,我有一个设计,使用了享元模式来共享位图,这些位图被位图对象共享,这些对象管理绘制操作,并集成在GUI库中。由于这是一个嵌入式设备,内存非常宝贵。目前,我已经使用一个轻量级类的auto_ptr std::vector实现了工作,该类计算使用情况。我知道这是一个不好的想法,可能会泄漏,所以我正在重新编写这部分内容。我考虑使用boost::shared_ptr。我的问题关键是,如果没有使用,我希望位图被释放。如果我有一个shared_ptr池,我最终只加载一次使用的位图。我考虑使用shared_ptr::use_count()来删除位图,如果use_count() == 1。但文档警告不要在生产代码中使用use_count()。基本上,这个问题是关于释放单个重对象的享元模式。你认为有更好的方法吗?


1
你不能在标准容器中使用std::auto_ptr,因为它们不支持复制语义(只支持移动语义)。 - Martin York
我认为STL真的缺乏ptr_containers。对于重型对象,所有复制都是低效的,最终你会在容器的析构函数中处理内存管理。 - piotr
2个回答

7
您可以使用一组boost弱指针来实现池,这样池就不会计入所有权。
只有位图对象有boost共享指针,这样它们决定何时释放位图。
弱指针池允许我们检索已经构造的位图:
当您创建位图对象时,您可以选择:
  • 如果弱指针不为空,则从弱指针获取共享指针,

  • 否则加载新位图,从中创建新的共享指针,并将弱指针插入/替换到池中。

以下是使用映射作为池的示例代码:
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <map>
#include <string>
#include <iostream>

// represents the bitmap data
class Bitmap
{
public :
    Bitmap( std::string const& name ) : name( name )
    {
        std::cout << "Bitmap " << name << std::endl ;
    }

    ~Bitmap()
    {
        std::cout << "~Bitmap " << name << std::endl ;
    }

    std::string name ;
};

// the flyweight pool
class Factory
{
public :

    typedef std::map< std::string , boost::weak_ptr< Bitmap > > Map ;

    boost::shared_ptr< Bitmap > get( std::string const& what )
    {
        Map::iterator x = map.find( what );

        // retrieve existing object from map's weak pointers

        if( x != map.end() )
        {
            if( boost::shared_ptr< Bitmap > shared = x->second.lock() )
            {
                return shared ;
            }
        }

        // populate or update the map

        boost::shared_ptr< Bitmap > shared( new Bitmap( what ) );
        boost::weak_ptr< Bitmap > weak( shared );
        map.insert( std::make_pair( what , weak ) );
        return shared ;
    }

private :
    Map map ;
};


int main(int argc, char** argv)
{
    Factory f ;

    // we try our flyweight bitmap factory ...

    boost::shared_ptr< Bitmap > a = f.get( "a" );
    boost::shared_ptr< Bitmap > b = f.get( "b" );

    // a is not made again
    boost::shared_ptr< Bitmap > a2 = f.get( "a" );

    a.reset();
    a2.reset();

    // a is destroyed before ------

    std::cout << "------" << std::endl ;
}

我喜欢它。但是我认为增加一些描述会更好。 - Martin York
我认为这是一个非常好的想法!我没有想到可以这样使用weak_ptrs。我目前使用use_count()使其正常工作,看起来没有泄漏。我会尝试使用weak_ptr解决方案,看看它是否确实有效。 - piotr
没有必要使用这段代码,但它非常简洁和优秀。谢谢。 - piotr

0
shared_ptr 的概念是它可以为您管理对象的生命周期。您不应该检查使用计数。每个用户都应该有一个 shared_ptr,当您删除用户时,请删除 shared_ptrs,当没有更多用户时,它将为您删除位图。如果您有一个特殊的例程需要调用以删除位图,并且不能在析构函数中执行该操作,则可以在创建 shared_ptr 时传递一个特殊的删除器函数。

你没有理解重点,如果一个 shared_ptr 仍然存在,那么一组重对象池将不会在使用后被删除。 - piotr
共享指针的集合可以有效地成为池。这正是它们设计的目的,作为对被共享的大型对象的引用,并在没有任何引用时删除对象。 - Kylotan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接