Однопоточный smart-ptr с подсчетом ссылок.
От: Аноним  
Дата: 25.11.05 13:31
Оценка:
Никто не подскажет, где взять сабж?
Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.
Re: Однопоточный smart-ptr с подсчетом ссылок.
От: Bell Россия  
Дата: 25.11.05 13:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Никто не подскажет, где взять сабж?

А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.


Loki уже смотрел?
Любите книгу — источник знаний (с) М.Горький
Re[2]: Однопоточный smart-ptr с подсчетом ссылок.
От: Аноним  
Дата: 25.11.05 13:46
Оценка:
Здравствуйте, Bell, Вы писали:

B>Loki уже смотрел?


В данный момент смотрю... Не нравится, что там хидером не отделаться — бюст в проекте уже есть, а вот локи тащить...
Правда там всего-то 4 файла получается. Лан, щас поглядим что получится.

Спасибо за наводку.

А все-таки, можно в бусте синхронизацию обрубить? (не в рамках всего проекта, а в данной единице трансляции)
Re: Однопоточный smart-ptr с подсчетом ссылок.
От: MaximE Великобритания  
Дата: 25.11.05 17:00
Оценка:
On Fri, 25 Nov 2005 13:31:10 -0000, wrote:

> Никто не подскажет, где взять сабж?

> Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

http://rsdn.ru/Forum/?mid=674518
Автор: MaximE
Дата: 10.06.04


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re: Однопоточный smart-ptr с подсчетом ссылок.
От: Аноним  
Дата: 25.11.05 17:28
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.

#define BOOST_DISABLE_THREADS

разве не для этого?
Re: Однопоточный smart-ptr с подсчетом ссылок.
От: alexeiz  
Дата: 25.11.05 23:02
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Никто не подскажет, где взять сабж?

А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.


shared_ptr счётчик ссылок поддерживается с помощью atomic операций. У тебя есть подозрения, что это слишком дорого?
Re: Однопоточный smart-ptr с подсчетом ссылок.
От: Linuxoid  
Дата: 26.11.05 18:11
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Никто не подскажет, где взять сабж?

А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

А>Скажем, нужен 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 pointer
    long * m_pRef;    // reference counter
};

#endif //__COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_
Re[2]: Однопоточный smart-ptr с подсчетом ссылок.
От: _Winnie Россия C++.freerun
Дата: 26.11.05 20:42
Оценка: 6 (3) +1
Здравствуйте, Linuxoid, Вы писали:

L>Здравствуйте, Аноним, Вы писали:


А>>Никто не подскажет, где взять сабж?

А>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.

1) Нет слабых ссылок, у которых можно узнать, жив ли еще объект или нет. Если их нет, то счетчик хранить на хипе не нужно. (Кстати, для интрузивности вовсе не надо создавать зависимости от "Базового _ref_counted_base_class"
1.1) Раз уж счетчик неинтруизивный, то еще было бы здорово сделать виртуальный deleter — расхода никакого (учитывая гранулярность хипа), а удовольствия море — можно передавать между разными DLL с разным менеджером памяти. Или вообще, сделать какую-то особенную функцию удаления.
Ну а раз это не нужно, то нафиг-то счетчик на хипе?
2) Классический баг, вот этот код падает —
struct GUIWindowsTree
{
    std::vector<_countable<GUIWindowsTree> > childs;
};

int main()
{
    _countable<GUIWindowsTree> p_wnd_tree(new GUIWindowsTree);
    p_wnd_tree->childs.push_back(_countable<GUIWindowsTree>(new GUIWindowsTree));
    p_wnd_tree->childs.push_back(_countable<GUIWindowsTree>(new GUIWindowsTree));
    p_wnd_tree = p_wnd_tree->childs[1];
}

3)
Нету возможности сделать что-то вроде


_countable<Base> fabric_function()
{
   return _countable<Derived>(new  Derived);
}


_countable<BaseOfBase> p = fabric_function();



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
Re[2]: Однопоточный smart-ptr с подсчетом ссылок.
От: remark Россия http://www.1024cores.net/
Дата: 27.11.05 12:48
Оценка:
Здравствуйте, Linuxoid, Вы писали:

L>Здравствуйте, Аноним, Вы писали:


А>>Никто не подскажет, где взять сабж?

А>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

А>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.


L>Попробуй вот это. Автор я, сам с удовольствием пользуюсь. Класс используется в реальном коммерческом проекте.

L>Буду благодарен за любую конструктивную критику.


От него надо наследоваться?
Если не надо, то не понятно зачем деструктор виртуальный?
Если надо, то не понятно зачем конструкторы открытые?

Я предпочитаю производство велосипедов отдать на откуп профессиональным производителям велосипедов


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Однопоточный smart-ptr с подсчетом ссылок.
От: Аноним  
Дата: 04.01.07 06:47
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Здравствуйте, Linuxoid, Вы писали:


L>>Здравствуйте, Аноним, Вы писали:


А>>>Никто не подскажет, где взять сабж?

А>>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.
А>>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.

_W>1) Нет слабых ссылок, у которых можно узнать, жив ли еще объект или нет. Если их нет, то счетчик хранить на хипе не нужно. (Кстати, для интрузивности вовсе не надо создавать зависимости от "Базового _ref_counted_base_class"

_W>1.1) Раз уж счетчик неинтруизивный, то еще было бы здорово сделать виртуальный deleter — расхода никакого (учитывая гранулярность хипа), а удовольствия море — можно передавать между разными DLL с разным менеджером памяти. Или вообще, сделать какую-то особенную функцию удаления.
_W>Ну а раз это не нужно, то нафиг-то счетчик на хипе?
_W>2) Классический баг, вот этот код падает —
_W>
_W>struct GUIWindowsTree
_W>{
_W>    std::vector<_countable<GUIWindowsTree> > childs;
_W>};

_W>int main()
_W>{
_W>    _countable<GUIWindowsTree> p_wnd_tree(new GUIWindowsTree);
_W>    p_wnd_tree->childs.push_back(_countable<GUIWindowsTree>(new GUIWindowsTree));
_W>    p_wnd_tree->childs.push_back(_countable<GUIWindowsTree>(new GUIWindowsTree));
_W>    p_wnd_tree = p_wnd_tree->childs[1];
_W>}
_W>

_W>3)
_W>Нету возможности сделать что-то вроде

_W>

_W>_countable<Base> fabric_function()
_W>{
_W>   return _countable<Derived>(new  Derived);
_W>}


_W>_countable<BaseOfBase> p = fabric_function();


_W>



_W>4) Тебе нужно срочно бежать за Саттером и его Exceptional C++, потому что два твоих мега-оператора присваивания в 30 строчек можно записать в две строчки-

_W>
_W>_countable(Y).swap(*this);
_W>return (*this);
_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 counter

    void 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_
Re: Однопоточный smart-ptr с подсчетом ссылок.
От: Аноним  
Дата: 08.01.07 09:16
Оценка: -1
////////////////////////////////////////////////////////////////////////////////////
// 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.
// -----------------------------------------------------------------------
// [16.12.2006] TODO!
// Known bug - code similar to this cause crash:
//
//      struct GUIWindowsTree
//      {
//          std::vector< countable< GUIWindowsTree > > childs;
//      };
//
//      void foo()
//      {
//          countable< GUIWindowsTree > p_wnd_tree( new GUIWindowsTree );
//          p_wnd_tree->childs.push_back( 
//              countable< GUIWindowsTree >( new GUIWindowsTree )
//          );
//          p_wnd_tree = p_wnd_tree->childs[0];
//      }
//
// -----------------------------------------------------------------------
// [16.12.2006] TODO!
// Assignment operators implements like this (Satter, "Exceptional C++").
//      {
//          countable(Y).swap(*this);
//          return (*this);
//      }
// -----------------------------------------------------------------------
// [04.01.2007]
// swap() function was added. Bugs fixed in assignment operators.
// 
#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 
{
private:

    T * m_pObj;     // pointer to stored object 
    long * m_pRef;  // usage counter
    
    void 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 * 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()
    {
        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( void )
    {
        return ++( *m_pRef );
    }
    
    long __decrement( void )
    {
        if( --( *m_pRef ))
        {
            return ( *m_pRef );
        }
                
        delete m_pObj, m_pObj = NULL;
        delete m_pRef, m_pRef = NULL;

        return 0;
    }
};

#endif //__COUNTABLE_H_A1ECF5CC_FDB0_4f27_9D50_7F75C07AF8F4_INCLUDED_
Re: Однопоточный smart-ptr с подсчетом ссылок.
От: LogRusAdm Россия  
Дата: 09.01.07 11:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Никто не подскажет, где взять сабж?

А>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

А>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.


shared_ptr не содержит синхронизации
с синхронизацией thread_specific_ptr
Re[2]: Однопоточный smart-ptr с подсчетом ссылок.
От: Константин Л.  
Дата: 09.01.07 12:01
Оценка:
Здравствуйте, LogRusAdm, Вы писали:

LRA>Здравствуйте, Аноним, Вы писали:


А>>Никто не подскажет, где взять сабж?

А>>Синхронизация не нужна. Нужен неинтрузивный подсчет ссылок на объекты.

А>>Скажем, нужен boost::shared_ptr с отключенной синхронизацией. или способ отключить ее без хирургического вмешательства.


LRA>shared_ptr не содержит синхронизации


если под синхронизацией понимался вызов InterlockedXXX для счетчиков — то она есть

LRA>с синхронизацией thread_specific_ptr
Re[3]: Однопоточный smart-ptr с подсчетом ссылок.
От: LogRusAdm Россия  
Дата: 09.01.07 12:24
Оценка:
LRA>>shared_ptr не содержит синхронизации

КЛ>если под синхронизацией понимался вызов InterlockedXXX для счетчиков — то она есть


Действительно где-то вглубено есть, прошу прощенья за дезинформацию, но для софтины без многопоточности, он не использует InterlockedXXX.
Можно явно оперделить
#define BOOST_SP_DISABLE_THREADS
перед включением заголовочного файла
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.