Pattern InstancePool
От: BULAT GAIFULLIN Россия  
Дата: 22.07.10 18:36
Оценка:
Хочу предложить вашему внимание паттерн проектирования InstanceManager;
Данный класс позволяет использовать только один экземпляр любого класса в программе не прибегая к помощи синглтонов:

//////////////////////////////////////////////////////////////////////////
// Therading model class example
struct SingleThread
{
  void Lock() {}
  void Unlock() {}
};

template <class T>
struct MutexLocker
{
  MutexLocker(T& m) : MyMutex(&m) { MyMutex->Lock(); };
  ~MutexLocker() { MyMutex->Unlock(); }
private:
  T* MyMutex;
};
//////////////////////////////////////////////////////////////////////////
/// class Instance pool

template<class ThreadingModel = SingleThread>
class InstanceManager
{
  class InstanceBase
  {
  public:
    virtual ~InstanceBase() {}
  };

  template <class T>
  class Instance : public T, public InstanceBase
  {
  };
public:
  ~InstanceManager()
  {
    while (!ObjectPool.empty())
    {
      delete ObjectPool.begin()->second;
      ObjectPool.erase(ObjectPool.begin());
    }
  }
  template <class T>
  T* GetInstance(const T* t = 0)
  {
    const Loki::TypeInfo id(typeid(t));
    ObjectPoolMap::iterator o = ObjectPool.find(id);
    if (o == ObjectPool.end())
    {
      MutexLocker<ThreadingModel> locker(InsertMutex);
      o = ObjectPool.find(id);
      if (o == ObjectPool.end())
      {
        o = ObjectPool.insert(ObjectPoolMap::value_type(id, new Instance<T>())).first;
      }
    }
    return static_cast<T*>(static_cast<Instance<T>* >(o->second));
  }
private:
  ThreadingModel InsertMutex;
  typedef std::map<Loki::TypeInfo, InstanceBase*> ObjectPoolMap;
  ObjectPoolMap ObjectPool;
};


пример использования:

class TestClass
{
public:
  TestClass() { std::cout<< "TestClass" << std::endl;  }
  virtual ~TestClass() { std::cout<< "~TestClass" << std::endl;  }
  void Print() { std::cout<< "TestClass::Print" << std::endl;  }
};

class TestClass2
{
public:
  TestClass2() { std::cout<< "TestClass2" << std::endl;  }
  virtual ~TestClass2() { std::cout<< "~TestClass2" << std::endl;  }
  void Print() { std::cout<< "TestClass2::Print" << std::endl;  }
};

void TestProgramm()
{
  InstanceManager<SingleThreading> manager;
  manager.GetInstance<TestClass>()->Print();
  manager.GetInstance<TestClass2>()->Print();
  manager.GetInstance<TestClass>()->Print();
  manager.GetInstance<TestClass2>()->Print();
  return 0;
}





класс TypeInfo, код взят из библиотеки Loki

namespace Loki
{
  class TypeInfo
  {
  public:
    // Constructors
    TypeInfo(); // needed for containers
    TypeInfo(const std::type_info&); // non-explicit

    // Access for the wrapped std::type_info
    const std::type_info& Get() const;
    // Compatibility functions
    bool before(const TypeInfo& rhs) const;
    const char* name() const;

  private:
    const std::type_info* pInfo_;
  };

  // Implementation

  inline TypeInfo::TypeInfo()
  {
    class Nil {};
    pInfo_ = &typeid(Nil);
    assert(pInfo_);
  }

  inline TypeInfo::TypeInfo(const std::type_info& ti)
  : pInfo_(&ti)
  { assert(pInfo_); }

  inline bool TypeInfo::before(const TypeInfo& rhs) const
  {
    assert(pInfo_);
    // type_info::before return type is int in some VC libraries 
    return pInfo_->before(*rhs.pInfo_) != 0;
  }

  inline const std::type_info& TypeInfo::Get() const
  {
    assert(pInfo_);
    return *pInfo_;
  }

  inline const char* TypeInfo::name() const
  {
    assert(pInfo_);
    return pInfo_->name();
  }

  // Comparison operators

  inline bool operator==(const TypeInfo& lhs, const TypeInfo& rhs)
  // type_info::operator== return type is int in some VC libraries
  { return (lhs.Get() == rhs.Get()) != 0; }

  inline bool operator<(const TypeInfo& lhs, const TypeInfo& rhs)
  { return lhs.before(rhs); }

  inline bool operator!=(const TypeInfo& lhs, const TypeInfo& rhs)
  { return !(lhs == rhs); }    

  inline bool operator>(const TypeInfo& lhs, const TypeInfo& rhs)
  { return rhs < lhs; }

  inline bool operator<=(const TypeInfo& lhs, const TypeInfo& rhs)
  { return !(lhs > rhs); }

  inline bool operator>=(const TypeInfo& lhs, const TypeInfo& rhs)
  { return !(lhs < rhs); }
}
Re: Pattern InstancePool
От: bnk СССР http://unmanagedvisio.com/
Дата: 22.07.10 18:43
Оценка:
Здравствуйте, BULAT GAIFULLIN, Вы писали:

BG>Хочу предложить вашему внимание паттерн проектирования InstanceManager;

BG>Данный класс позволяет использовать только один экземпляр любого класса в программе не прибегая к помощи синглтонов:

Я думал, паттерн — это вроде как картинка, ну, или там, описание..? А тут код какой-то
Re: Pattern InstancePool
От: Sni4ok  
Дата: 22.07.10 19:01
Оценка:
Здравствуйте, BULAT GAIFULLIN, Вы писали:

BG>Хочу предложить вашему внимание паттерн проектирования InstanceManager;


бред какой-то, для получения доступа к обьекту происходит синхронизация, а ещё и поиск по мапе, тоесть ужасная писсимизация на пустом месте,
если не нравятся синглетоны майерса с неопределённым временем жизни- создайте обьект-синглетон на стеке, проинициализируйте глобальный указатель, а потом используйте где угодно, это и проще и понятнее и намного быстрее.
Re: Pattern InstancePool
От: TarasKo Голландия  
Дата: 22.07.10 21:11
Оценка:
Про то насколько нужна эта штуковина, ничего не буду говорить.
А в коде углядел вот что

1. Какая-то муть с блокировкой + 2 раза find

  template <class T>
  T* GetInstance(const T* t = 0)
  {
    MutexLocker<ThreadingModel> locker(InsertMutex);

    const Loki::TypeInfo id(typeid(t));
    ObjectPoolMap::iterator o = ObjectPool.find(id);
    if (o == ObjectPool.end())
    {
        o = ObjectPool.insert(ObjectPoolMap::value_type(id, new Instance<T>())).first;
    }

    return static_cast<T*>(static_cast<Instance<T>* >(o->second));
  }


2.
Страная смесь стратегий, локера и мьютека
MutexLocker<ThreadingModel> locker(InsertMutex);

Разумнее было бы вообще не иметь мутекса в случае одного потока.
Re: Pattern InstancePool
От: Caracrist https://1pwd.org/
Дата: 23.07.10 03:32
Оценка:
Здравствуйте, BULAT GAIFULLIN, Вы писали:

BG>Хочу предложить вашему внимание паттерн проектирования InstanceManager;

BG>Данный класс позволяет использовать только один экземпляр любого класса в программе не прибегая к помощи синглтонов:


BG>    const Loki::TypeInfo id(typeid(t));
BG>    ObjectPoolMap::iterator o = ObjectPool.find(id);

интересно о чём нам расскажет этот find если ему по серединке пару инсертов сделать ...
BG>    if (o == ObjectPool.end())
BG>    {
BG>      MutexLocker<ThreadingModel> locker(InsertMutex);
BG>      o = ObjectPool.find(id);
BG>      if (o == ObjectPool.end())
BG>      {
BG>        o = ObjectPool.insert(ObjectPoolMap::value_type(id, new Instance<T>())).first;
BG>      }
BG>    }
BG>    return static_cast<T*>(static_cast<Instance<T>* >(o->second));


а сам класс будет статиком или синглтоном?

п.с. try again later
~~~~~
~lol~~
~~~ Single Password Solution
Re[2]: Pattern InstancePool
От: BULAT GAIFULLIN Россия  
Дата: 23.07.10 09:52
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>Здравствуйте, BULAT GAIFULLIN, Вы писали:


BG>>Хочу предложить вашему внимание паттерн проектирования InstanceManager;

BG>>Данный класс позволяет использовать только один экземпляр любого класса в программе не прибегая к помощи синглтонов:

C>

BG>>    const Loki::TypeInfo id(typeid(t));
BG>>    ObjectPoolMap::iterator o = ObjectPool.find(id);

C>интересно о чём нам расскажет этот find если ему по серединке пару инсертов сделать ...
C>
BG>>    if (o == ObjectPool.end())
BG>>    {
BG>>      MutexLocker<ThreadingModel> locker(InsertMutex);
BG>>      o = ObjectPool.find(id);
BG>>      if (o == ObjectPool.end())
BG>>      {
BG>>        o = ObjectPool.insert(ObjectPoolMap::value_type(id, new Instance<T>())).first;
BG>>      }
BG>>    }
BG>>    return static_cast<T*>(static_cast<Instance<T>* >(o->second));

C>


здесь нужно лочить еще перед первым вызовом find. моя ошибка.

C>а сам класс будет статиком или синглтоном?


я собирался сделать сам класс является синглтоном.

C>п.с. try again later
Re[2]: Pattern InstancePool
От: Кодт Россия  
Дата: 24.07.10 11:00
Оценка:
Здравствуйте, Sni4ok, Вы писали:

S>писсимизация


Какое прекрасное слово!
Почти пессимизация, только гораздо экспрессивнее.

S>если не нравятся синглетоны майерса с неопределённым временем жизни- создайте обьект-синглетон на стеке, проинициализируйте глобальный указатель, а потом используйте где угодно, это и проще и понятнее и намного быстрее.


У Александреску (раз уж Локи было упомянуто) разных синглетонов с разными стратегиями жизни было — вагон и тележка.
Перекуём баги на фичи!
Re: Pattern InstancePool
От: MrVoid  
Дата: 24.07.10 23:10
Оценка:
"Паттерном" это вообще вряд ли можно было бы назвать, так как паттерн здесь уже есть — это синглтон.

Решение обладает следующими недостатками:

1. Дикая неэффективность: каждое обращение к экземпляру — поиск в std::map. Это делает данное решение практически непригодным.
2. Неудобная длинная запись при получении экземпляра.
3. Модель многопоточности задается для всех синглтонов сразу, а не для каждого в отдельности.

Да и вообще, непонятно для каких целей это нужно. Для тех, у кого в программе очень много синглтонов? В нормальной программе будет от силы несколько синглтонов, причем приоритетом часто является скорость доступа к экземпляру.

Кстати, такую же функциональность, как в вашем примере, можно получить таким элементарным кодом (только он гораздо эффективнее):

template <class Type>
inline Type& GetInstance()
{
    static Type instance;
    return instance;
}


(Если нужна многопоточность, тело функции соответствующим образом изменить).
Re[2]: Pattern InstancePool
От: BULAT GAIFULLIN Россия  
Дата: 26.07.10 07:55
Оценка:
Здравствуйте, MrVoid, Вы писали:
MV>Кстати, такую же функциональность, как в вашем примере, можно получить таким элементарным кодом (только он гораздо эффективнее):

MV>
MV>template <class Type>
MV>inline Type& GetInstance()
MV>{
MV>    static Type instance;
MV>    return instance;
MV>}
MV>


MV>(Если нужна многопоточность, тело функции соответствующим образом изменить).



ваш пример не компилируем, поскольку перегрузка по типу возвращаемого значения в С++ не предусмотренна.

по крайней мере вот так:
template<class T>
inline T& GetInstance(const T* = 0)
{
  static T instance;
  return instance;
}


и безопасность при многопоточности в данном примере тоже не совсем понятно как реализовывать?
Re[3]: Pattern InstancePool
От: Guard_h4s Россия  
Дата: 26.07.10 08:20
Оценка:
Здравствуйте, BULAT GAIFULLIN, Вы писали:

BG>и безопасность при многопоточности в данном примере тоже не совсем понятно как реализовывать?

Между прочим, кроме внешней синхронизации существует и внутренняя. В данном случае вполне нормально сделать тип Т потокобезопасным.
(Только статиком тут лучше делать указатель и инициализировать его явно)
Re[3]: Pattern InstancePool
От: Кодт Россия  
Дата: 26.07.10 08:50
Оценка:
Здравствуйте, BULAT GAIFULLIN, Вы писали:

MV>>
MV>>template <class Type>
MV>>inline Type& GetInstance()
MV>>

BG>ваш пример не компилируем, поскольку перегрузка по типу возвращаемого значения в С++ не предусмотренна.
BG>по крайней мере вот так:
BG>
BG>template<class T>
BG>inline T& GetInstance(const T* = 0)
BG>


Это не перегрузка.
Разумеется, если написать x=GetInstance(), то компилятор не сможет победить неоднозначность.
А вот если x=GetInstance<Foo>() — всё будет хорошо.


BG>и безопасность при многопоточности в данном примере тоже не совсем понятно как реализовывать?


О, это давняя тема — как сделать синглетон Мейерса потокобезопасным.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.