Здравствуйте, Аноним, Вы писали:
А>Никто не подскажет, где взять сабж? А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
Loki уже смотрел?
Любите книгу — источник знаний (с) М.Горький
Re[2]: Однопоточный smart-ptr с подсчетом ссылок.
От:
Аноним
Дата:
25.11.05 13:46
Оценка:
Здравствуйте, Bell, Вы писали:
B>Loki уже смотрел?
В данный момент смотрю... Не нравится, что там хидером не отделаться — бюст в проекте уже есть, а вот локи тащить...
Правда там всего-то 4 файла получается. Лан, щас поглядим что получится.
Спасибо за наводку.
А все-таки, можно в бусте синхронизацию обрубить? (не в рамках всего проекта, а в данной единице трансляции)
On Fri, 25 Nov 2005 13:31:10 -0000, wrote:
> Никто не подскажет, где взять сабж? > Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
Здравствуйте, Аноним, Вы писали:
А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
Здравствуйте, Аноним, Вы писали:
А>Никто не подскажет, где взять сабж? А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
shared_ptr счётчик ссылок поддерживается с помощью atomic операций. У тебя есть подозрения, что это слишком дорого?
Здравствуйте, Аноним, Вы писали:
А>Никто не подскажет, где взять сабж? А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
Попробуй вот это. Автор я, сам с удовольствием пользуюсь. Класс используется в реальном коммерческом проекте.
Буду благодарен за любую конструктивную критику.
////////////////////////////////////////////////////////////////////////////////////
// countable.h
//
// Author: Vitaliy Ivanchenko, <vtal@ukr.net>
// Copyright (c) Kiev, 2005
//
// Implementation of class that stores a pointer to allocated object of type T.
// The stored pointer must either be NULL or designate an object allocated by a new
// expression.
//
////////////////////////////////////////////////////////////////////////////////////
//
// History
// _________________________________________________________________________________
//
// [15.07.2005]
// _countable class was implemented.
// -----------------------------------------------------------------------
// [19.07.2005]
// Bugs were fixed in assignment operator:
// 1) Release of the stored object performed incorrectly before copying.
// 2) Memory used for reference counter was not free if the object is
// the same but counters are different.
// -----------------------------------------------------------------------
// [22.10.2005]
// Bug was fixed in assignment operator:
// Memory used for reference counter was not release if pointer to stored
// object equals NULL.
// -----------------------------------------------------------------------
// [22.10.2005]
// Assignment operator of pointer to countable object was implemented.
// -----------------------------------------------------------------------
//#if !defined(__COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_)
#define __COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_
#include <assert.h>
template <typename T> class _countable
{
public:
typedef T element_type;
//
// Default constructor
//explicit _countable(T * p = 0) throw() : m_pObj(p), m_pRef(NULL)
{
m_pRef = new long(0L);
_increment();
}
//
// Copying constructor
//
_countable(const _countable<T>& Y) throw() : m_pObj(Y.m_pObj), m_pRef(Y.m_pRef)
{
_increment();
}
//
// Assignment operators
//
_countable<T>& operator=(const _countable<T>& Y) throw()
{
if (this != &Y)
{
if (m_pObj != Y.get())
{
_decrement();
m_pObj = Y.get();
m_pRef = Y.m_pRef;
_increment();
}
else if (m_pRef != Y.m_pRef)
{
//
// Usage counter (i.e. value of *m_pRef) must be equal to 1 always here;
// otherwise we have unsolvable problem caused by incorrect _countable usage.
//
assert(1 == *m_pRef);
if (1 == *m_pRef) delete m_pRef;
m_pRef = Y.m_pRef;
_increment();
}
}
return (*this);
}
_countable<T>& operator=(typename T * pT) throw()
{
if( m_pObj != pT )
{
_decrement();
m_pRef = new long(0L);
m_pObj = pT;
_increment();
}
return (*this);
}
//
// Destructor
//virtual ~_countable()
{
_decrement();
}
T& operator*() const throw()
{
return (*get());
}
T *operator->() const throw()
{
return (get());
}
T *get() const throw()
{
return m_pObj;
}
long _increment()
{
return ++(*m_pRef);
}
long _decrement()
{
if (--(*m_pRef)) return (*m_pRef);
//
// Do something useful when counter reaches 0 (e.g. destroy object)
//delete m_pObj;
delete m_pRef;
return 0;
}
private:
T * m_pObj; // storage object pointerlong * m_pRef; // reference counter
};
#endif//__COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_
Здравствуйте, Linuxoid, Вы писали:
L>Здравствуйте, Аноним, Вы писали:
А>>Никто не подскажет, где взять сабж? А>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты. А>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
1) Нет слабых ссылок, у которых можно узнать, жив ли еще объект или нет. Если их нет, то счетчик хранить на хипе не нужно. (Кстати, для интрузивности вовсе не надо создавать зависимости от "Базового _ref_counted_base_class"
1.1) Раз уж счетчик неинтруизивный, то еще было бы здорово сделать виртуальный deleter — расхода никакого (учитывая гранулярность хипа), а удовольствия море — можно передавать между разными DLL с разным менеджером памяти. Или вообще, сделать какую-то особенную функцию удаления.
Ну а раз это не нужно, то нафиг-то счетчик на хипе?
2) Классический баг, вот этот код падает —
4) Тебе нужно срочно бежать за Саттером и его Exceptional C++, потому что два твоих мега-оператора присваивания в 30 строчек можно записать в две строчки-
_countable(Y).swap(*this);
return (*this);
5) m_pRef = new long(0L); — не exception safe. Если этот new кинет исключение, указатель переданный во владение _countable, утечёт.
Может и не всё, это то, что на glance взгляд. Еще есть другие мелочи, но они не опасны, и если они не нужны то и нафиг их.
ИМХО, лучше взять boost::shared_ptr — функциональность в четыре раза больше, он документирован и скоро войдёт в стандарт, есть большой шанс, что другие С++ его знают, он не имеет тонких багов вроде того, который я показал выше. И его многопоточность можно отключить, порывшись в boost-1_33\boost\detail\interlocked.hpp. Это лучше, чем отлавливать баги в чужих smart_ptr, и расширять их функциональность.
Правильно работающая программа — просто частный случай Undefined Behavior
Здравствуйте, Linuxoid, Вы писали:
L>Здравствуйте, Аноним, Вы писали:
А>>Никто не подскажет, где взять сабж? А>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
L>Попробуй вот это. Автор я, сам с удовольствием пользуюсь. Класс используется в реальном коммерческом проекте. L>Буду благодарен за любую конструктивную критику.
От него надо наследоваться?
Если не надо, то не понятно зачем деструктор виртуальный?
Если надо, то не понятно зачем конструкторы открытые?
Я предпочитаю производство велосипедов отдать на откуп профессиональным производителям велосипедов
Здравствуйте, _Winnie, Вы писали:
_W>Здравствуйте, Linuxoid, Вы писали:
L>>Здравствуйте, Аноним, Вы писали:
А>>>Никто не подскажет, где взять сабж? А>>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты. А>>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
_W>1) Нет слабых ссылок, у которых можно узнать, жив ли еще объект или нет. Если их нет, то счетчик хранить на хипе не нужно. (Кстати, для интрузивности вовсе не надо создавать зависимости от "Базового _ref_counted_base_class" _W>1.1) Раз уж счетчик неинтруизивный, то еще было бы здорово сделать виртуальный deleter — расхода никакого (учитывая гранулярность хипа), а удовольствия море — можно передавать между разными DLL с разным менеджером памяти. Или вообще, сделать какую-то особенную функцию удаления. _W>Ну а раз это не нужно, то нафиг-то счетчик на хипе? _W>2) Классический баг, вот этот код падает — _W>
_W>4) Тебе нужно срочно бежать за Саттером и его Exceptional C++, потому что два твоих мега-оператора присваивания в 30 строчек можно записать в две строчки- _W>
_W>5) m_pRef = new long(0L); — не exception safe. Если этот new кинет исключение, указатель переданный во владение _countable, утечёт.
_W>Может и не всё, это то, что на glance взгляд. Еще есть другие мелочи, но они не опасны, и если они не нужны то и нафиг их.
_W>ИМХО, лучше взять boost::shared_ptr — функциональность в четыре раза больше, он документирован и скоро войдёт в стандарт, есть большой шанс, что другие С++ его знают, он не имеет тонких багов вроде того, который я показал выше. И его многопоточность можно отключить, порывшись в boost-1_33\boost\detail\interlocked.hpp. Это лучше, чем отлавливать баги в чужих smart_ptr, и расширять их функциональность.
////////////////////////////////////////////////////////////////////////////////////
// countable.h
//
// Implementation of class that stores a pointer to allocated object of type T.
// The stored pointer must either be NULL or designate an object allocated by a new
// expression. Can be used for storing objects in STL containers.
//
////////////////////////////////////////////////////////////////////////////////////
//
// History
// _________________________________________________________________________________
//
// [15.07.2005]
// countable class was implemented.
// -----------------------------------------------------------------------
// [19.07.2005]
// Bugs were fixed in assignment operator:
// 1) Release of the stored object performed incorrectly before copying.
// 2) Memory used for reference counter was not free if the object is
// the same but counters are different.
// -----------------------------------------------------------------------
// [22.10.2005]
// Bug was fixed in assignment operator:
// Memory used for reference counter was not release if pointer to stored
// object equals NULL.
// -----------------------------------------------------------------------
// [22.10.2005]
// Assignment operator of pointer to countable object was implemented.
// -----------------------------------------------------------------------
// [04.01.2007]
// Added swap() function. Bugs fixed in assignment operators.
//
//#if !defined(__COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_)
#define __COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_
template < typename T > class countable
{
private:
T * m_pObj; // pointer to stored object long * m_pRef; // usage countervoid swap( countable< T > & Y ) throw()
{
T * pObj = m_pObj;
long * pRef = m_pRef;
m_pObj = Y.m_pObj;
m_pRef = Y.m_pRef;
Y.m_pObj = pObj;
Y.m_pRef = pRef;
}
public:
typedef T element_type;
//
// Default constructor
//explicit countable( T * pT = 0 ) throw() : m_pObj( pT ), m_pRef( NULL )
{
m_pRef = new long( 0L );
increment();
}
//
// Copying constructor
//
countable( const countable< T >& Y ) throw() : m_pObj( Y.m_pObj ), m_pRef( Y.m_pRef )
{
increment();
}
//
// Assignment operators
//
countable< T >& operator=( const countable< T >& Y ) throw()
{
countable( Y ).swap( *this );
return ( *this );
}
countable< T >& operator=( typename T * pT ) throw()
{
countable( pT ).swap( *this );
return ( *this );
}
//
// Destructor
//virtual ~countable()
{
decrement();
}
//
// Overloaded operators
//
T& operator*() const throw()
{
return ( *get() );
}
T *operator->() const throw()
{
return ( get() );
}
T *get() const throw()
{
return m_pObj;
}
//
// The same as AddRef() and Release() in COM
//long increment()
{
return ++( *m_pRef );
}
long decrement()
{
if( --( *m_pRef ))
{
return ( *m_pRef );
}
//
// Delete object when reference counter reaches 0
//delete m_pObj, m_pObj = NULL;
delete m_pRef, m_pRef = NULL;
return 0;
}
};
#endif//__COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_
Здравствуйте, Аноним, Вы писали:
А>Никто не подскажет, где взять сабж? А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
shared_ptr не содержит синхронизации
с синхронизацией thread_specific_ptr
Здравствуйте, LogRusAdm, Вы писали:
LRA>Здравствуйте, Аноним, Вы писали:
А>>Никто не подскажет, где взять сабж? А>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
LRA>shared_ptr не содержит синхронизации
если под синхронизацией понимался вызов InterlockedXXX для счетчиков — то она есть
LRA>с синхронизацией thread_specific_ptr
LRA>>shared_ptr не содержит синхронизации
КЛ>если под синхронизацией понимался вызов InterlockedXXX для счетчиков — то она есть
Действительно где-то вглубено есть, прошу прощенья за дезинформацию, но для софтины без многопоточности, он не использует InterlockedXXX.
Можно явно оперделить
#define BOOST_SP_DISABLE_THREADS
перед включением заголовочного файла