Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Февраль 06, 2017, 12:20



Название: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 06, 2017, 12:20
Добрый день

Навеяно соседней темой. Простой пример имплисит шары
Код
C++ (Qt)
struct SomeClass {
..
QImage m_data;
..
};
И все здесь очень хорошо. И конструктор/деструктор по умолчанию, и isNull есть, и копируется по-умному. Но вот беда - m_data не может быть полиморфной, это только QImage и ничто иное. Нельзя ли это как-то (творчески) переработать в умный указатель чтобы иметь возможность
Код
C++ (Qt)
cow_ptr<SomeData> m_data;
...
m_data = new SomeDerivedData;
Т.е. тот же ф-ционал имплисит шары но с возможностью полиморфизма. Или это фантастика?

Спасибо


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 06, 2017, 12:27
Если вместо QImage использовать QVariant, то возможен динамический полиморфизм.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 06, 2017, 12:38
Еще можно использовать boost::any, который должен войти в C++17, как std::any.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Авварон от Февраль 06, 2017, 12:43
Вариант и эни не то, что нужно, они не дают корову.
Написать такой указатель можно (2мя способами - через наследование от интерфейса с методом clone() либо через мета-объектную систему, выцеплять конструктор копирования).
Не очень понятно, правда, какую задачу решает данный указатель.
Корова эмулирует value-based типы (которые копируются на стеке).
Шаред-птр и юник-птр (и любой другой птр) хранят указатели на уникальный объект (который не должен копироваться).
В чем смысл клонировать объект?

Upd: ну только могу придумать когда внешне это всё тот же value-based, а внутри полиморфная приватная дата (например, зависит от платформы, хз). Это делается через пару QSharedDataPointer на дату + std::unique_ptr на полиморфную часть в этой дате.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 06, 2017, 13:03
Не очень понятно, правда, какую задачу решает данный указатель.
Ту же самую (корову) что исходный пример с QImage но не завязан жестко на этот тип

Шаред-птр и юник-птр (и любой другой птр) хранят указатели на уникальный объект (который не должен копироваться).
У них не должен, у нас должен (при записи).


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 06, 2017, 13:31
Если вместо QImage использовать QVariant, то возможен динамический полиморфизм.
Еще можно использовать boost::any, который должен войти в C++17, как std::any.
Задача иметь обычный ф-ционал указателя (может указывать как на базовый тип так и на порожденный) но "одетый" в удобную оболочку вумного указателя. Хранить "все на свете" планов не было


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Авварон от Февраль 06, 2017, 13:38
Это не задача


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: __Heaven__ от Февраль 06, 2017, 14:16
Кажется, эта задача решается с помощью python


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 06, 2017, 15:08
Что-то плохо доходит. Еще раз. Вот мы написали так
Код
C++ (Qt)
struct SomeClass {
..
QImage m_data;
..
};
И все хорошо. Но вот выясняется что в одном из вариантов понадобился не QImage а его потомок напр MyImage. Наши действия?
Код
C++ (Qt)
QSharedPointer<QImage> m_data;
 
Но это совсем не то что нужно. Мы хотели имплисит шару, а не "уникальность". Да, копии SomeClass могут иметь свои копии m_data в рез-те их редактирования, никакой "общий ресурс" в наши планы не входил. А тут приходится объявлять шаред который совсем не шаред, а потом латать копирование для SomeClass  :'(


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Авварон от Февраль 06, 2017, 15:38
Ещё раз - какую задачу вы решаете?
COW решает задачу дешевого копирования объектов на стеке. То, что там внутри указатель мы знать не должны (просто абстракция весьма дырявая, поэтому приходиться знать как оно "под капотом").
shared_ptr решает задачу раздельного владения уникальным объектом.
unique_ptr решает задачу уникального владения уникальным объектом.
Что вы хотите сделать? Пример с куимаджем нерелевантен почти полностью, так как у него нет даже виртуальных методов (на самом деле, есть, но это врядли). Какой полиморфизм вы хотите от класса без виртуальных методов?


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Пантер от Февраль 06, 2017, 15:47
Igors, ты хочешь утиную типизацию?

Код
C++ (Qt)
class A {virtual foo () = 0;};
class B : public A {virtual foo() {};};
 
struct C
{
 C () : a (new B) {}
 A *a;
}
 
 

Но чтобы a была на стеке? Шаблон тогда нужен.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 06, 2017, 15:48
Проблема QImage и других подобных типов, что они реализуют implicit shared внутри, и не очень то располагают к дальнейшему наследованию. В случае Qt наследоваться приходится от скрытой приватной части, что мягко говоря неудобно.

А вообще можно использовать (написать самостоятельно) умный указатель, реализующий implicit shared технику, тогда корова останется коровой.

Код
C++ (Qt)
implicit_shared_ptr< Cow > cow = implicit_shared_ptr< MyCow >::make();
 

Внутри implicit_shared_ptr скроется непосредственно share_ptr и метод detach(), реализующий клонирование MyCow.
Так как предполагается клонирование экземпляра произвольного типа MyCow, то хранить придется не сам тип, а обертку Holder поверх его (подобно boost::any).


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Авварон от Февраль 06, 2017, 15:54
Igors, ты хочешь утиную типизацию?

Вот и я пытаюсь добиться, чего хоцца. В такой постановке уже 2 человека написали - коровный указатель, к-ый вызывает clone() у объекта когда надо.

Цитировать
If it walks like a duck, and quacks like a duck, it’s probably gonna throw exceptions at runtime.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 06, 2017, 16:46
Еще упростим (стоит статУя вообще без плюсов)
Код
C++ (Qt)
struct SomeClass {
..
BaseData * m_data;   // указатель на базовый класс
..
};
 
Типовая ситуация: SomeClass владеет BaseData и копии SomeClass имеют свои копии BaseData. Хотелось бы объявить m_data просто членом, но не выходит т.к. он полиморфный. Приходится объявлять указателем, тогда получаем серию мелких (пусть и не смертельных) забот - об этом указателе надо заботиться в конструкторе, деструкторе и при копировании. Также хотелось бы иметь корову на копировании. Вот собсно вся задача, что тут неясно ???

И вот я как-то не вижу как ее решить стандартными средствами. Все уперлись рогом в "уникальность", как будто других потребностей нет.

Проблема QImage и других подобных типов, что они реализуют implicit shared внутри, и не очень то располагают к дальнейшему наследованию.
Да, тоже думал об этом, прошивать методы ref/deref как-то не тянет, да и хотелось бы класс-содержимое в это не посвящать. Если вумный указатель, то все проходит через операторы ->, *, ну может и сделать их константными, а для записи юзать get() или data() и там расшаривать. Потому что так
Код
C++ (Qt)
template<class T>
struct cow_ptr {
...
T * operator -> ( void );
const T * operator -> ( void ) const;
...
};
 
cow_ptr<SomeData> ptr(new SomeData);
int a = ptr->mA;   // позовет неконстантный ->, сволочь такая
 


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Авварон от Февраль 06, 2017, 16:58
Еще упростим (стоит статУя вообще без плюсов)
Типовая ситуация: SomeClass владеет BaseData и копии SomeClass имеют свои копии BaseData. Хотелось бы объявить m_data просто членом, но не выходит т.к. он полиморфный. Приходится объявлять указателем, тогда получаем серию мелких (пусть и не смертельных) забот - об этом указателе надо заботиться в конструкторе, деструкторе и при копировании. Также хотелось бы иметь корову на копировании. Вот собсно вся задача, что тут неясно ???

И вот я как-то не вижу как ее решить стандартными средствами. Все уперлись рогом в "уникальность", как будто других потребностей нет.


Ну, это не решается стандартными средствами, потому что вы хотите 1 стандартное и 1 нестандартное средство совместить в одно.
Первое - нужен "вумный" указатель, который полиморфно клонирует объект
Код
C++ (Qt)
template<class T>
class MyPtr
{
   T *d;
   MyPtr(const MyPtr &other) : d(other.d->clone()) {}
};
 
Второе - собсно обычная корова (QSharedData+QSharedDataPointer), которая управляет МуПтром.
Код
C++ (Qt)
class SomeClass {
   SomeClassData : public QSharedData
   {
        MyPtr<BaseData> data;
   };
 
    QSharedPointer<SomeClassData> d;
};
 

И да, это уже 3й раз когда решение называется в этом треде.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 07, 2017, 12:01
Набросал на скорую руку такое решение.
Такое поведение имелось в виду?

Код
C++ (Qt)
#include <memory>
 
class AbstractHolder
{
public:
   using SharedAbstractHolder = std::shared_ptr< AbstractHolder >;
 
public:
   virtual ~AbstractHolder () {}
   virtual SharedAbstractHolder clone () const = 0;
};
 
template < typename _Type >
class Holder
   : public AbstractHolder
{
   using ThisType = Holder< _Type >;
   using ParentType = AbstractHolder;
 
public:
   using ValueType = _Type;
 
private:
   ValueType m_value;
 
public:
   template < typename ... _Arguments >
   Holder ( _Arguments && ... args )
   : m_value( std::forward< _Arguments >( args ) ... )
   {
   }
 
   const _Type & readable () const
   {
       return m_value;
   }
 
   _Type & writable ()
   {
       return m_value;
   }
 
   virtual SharedAbstractHolder clone () const
   {
       return std::make_shared< ThisType >( m_value );
   }
};
 
 
template < typename _Type >
class ImplicitWrapper
{
private:
   using ThisType = ImplicitWrapper< _Type >;
   using HolderType = Holder< _Type >;
   using SharedHolder = std::shared_ptr< AbstractHolder >;
   using SharedAbstractHolder = std::shared_ptr< AbstractHolder >;
 
   template < typename _OtherType >
   friend class ImplicitWrapper;
 
private:
   SharedHolder m_shared_holder;
 
private:
   ImplicitWrapper ( const SharedHolder & holder )
   : m_shared_holder( holder )
   {
   }
 
   void detach ()
   {
       if ( m_shared_holder.use_count() > 1 )
           m_shared_holder = m_shared_holder->clone();
   }
 
public:
   ImplicitWrapper ()
   : m_shared_holder()
   {
   }
 
   template < typename _OtherType >
   ImplicitWrapper ( const ImplicitWrapper< _OtherType > & other )
   : m_shared_holder( other.m_shared_holder )
   {
       static_assert( std::is_base_of< _Type, _OtherType >::value, "The types are not compatibile." );
   }
 
   bool isNull () const
   {
       return !m_shared_holder;
   }
 
   const _Type & readable () const
   {
       return std::static_pointer_cast< HolderType >( m_shared_holder )->readable();
   }
 
   _Type & writable ()
   {
       detach();
       return std::static_pointer_cast< HolderType >( m_shared_holder )->writable();
   }
 
public:
   template < typename ... _Arguments >
   static ThisType make ( _Arguments && ... args )
   {
       return ThisType( std::make_shared< Holder< _Type > >( std::forward< _Arguments >( args ) ... ) );
   }
};
 
#include <iostream>
 
struct Test
{
   Test ()
   {
       std::cout << "Constructor of Test" << std::endl;
   }
 
   Test ( const Test & )
   {
       std::cout << "Copy of Test" << std::endl;
   }
 
   Test ( Test && )
   {
       std::cout << "Move of Test" << std::endl;
   }
 
   virtual ~Test ()
   {
       std::cout << "Destructor of Test" << std::endl;
   }
 
   virtual void method ()
   {
       std::cout << "Mutable method of Test" << std::endl;
   }
 
   virtual void method () const
   {
       std::cout << "Constant method of Test" << std::endl;
   }
};
 
struct DerivedTest
   : public Test
{
   DerivedTest ()
   {
       std::cout << "Constructor of DerivedTest" << std::endl;
   }
 
   DerivedTest ( const DerivedTest & other )
   : Test( other )
   {
       std::cout << "Copy of DerivedTest" << std::endl;
   }
 
   DerivedTest ( DerivedTest && other )
   : Test( std::forward< Test >( other ) )
   {
       std::cout << "Move of DerivedTest" << std::endl;
   }
 
   virtual ~DerivedTest ()
   {
       std::cout << "Destructor of DerivedTest" << std::endl;
   }
 
   virtual void method ()
   {
       std::cout << "Mutable method of DerivedTest" << std::endl;
   }
 
   virtual void method () const
   {
       std::cout << "Constant method of DerivedTest" << std::endl;
   }
};
 
struct OtherTest
{
   OtherTest ()
   {
       std::cout << "Constructor of OtherTest" << std::endl;
   }
 
   ~OtherTest ()
   {
       std::cout << "Destructor of OtherTest" << std::endl;
   }
 
   void method ()
   {
       std::cout << "Mutable method of OtherTest" << std::endl;
   }
 
   void method () const
   {
       std::cout << "Constant method of OtherTest" << std::endl;
   }
};
 
int main ( int, char ** )
{
   // OK
   {
       ImplicitWrapper< Test > test_value = ImplicitWrapper< Test >::make();
       test_value.readable().method();
       test_value.writable().method();
   }
 
   // OK
   {
       ImplicitWrapper< Test > test_value = ImplicitWrapper< DerivedTest >::make();
       test_value.readable().method();
       test_value.writable().method();
   }
 
   // ERROR
//    {
//        ImplicitWrapper< Test > test_value = ImplicitWrapper< OtherTest >::make();
//        test_value.readable().method();
//        test_value.writable().method();
//    }
 
   // OK
   {
       ImplicitWrapper< DerivedTest > first_value = ImplicitWrapper< DerivedTest >::make();
       ImplicitWrapper< Test > second_value = first_value;
       second_value.readable().method();   // not detached
       second_value.writable().method();     // detached
   }
 
   // OK
   {
       ImplicitWrapper< Test > second_value = ImplicitWrapper< DerivedTest >::make( DerivedTest() );
       second_value.readable().method();
       second_value.writable().method();
   }
 
   return 0;
}
 


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 07, 2017, 13:35
Первое - нужен "вумный" указатель, который полиморфно клонирует объект
Код
C++ (Qt)
template<class T>
class MyPtr
{
   T *d;
   MyPtr(const MyPtr &other) : d(other.d->clone()) {}
};
 
А разве такое клонирование полиморфно? По-моему нет, ведь other может быть лишь того же типа T. Поправьте если не так

Второе - собсно обычная корова (QSharedData+QSharedDataPointer), которая управляет МуПтром.
Да, но делегировать на "d" хлопотно. Сравним с "нулевым вариантом" (голый указатель). В принципе и там все решаемо за 5-10 минут. Ну добавил по строчке в конструктор/деструктор. С копированием правда хужее - придется считать что BaseData имеет виртуальный метод clone(). Вот когда все эти сопельки убираются "легким движением руки" - гуд. А начинать долгую писанину из-за этого непривлекательно.

Набросал на скорую руку такое решение.
Такое поведение имелось в виду?
К сожалению, все никак не переползу на С++ 11, но по тексту вижу - да, такое. Никак нельзя убрать (или иначе оформить) эти readable/writeable? Спасибо

 



Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 07, 2017, 14:17
Набросал на скорую руку такое решение.
Такое поведение имелось в виду?
К сожалению, все никак не переползу на С++ 11, но по тексту вижу - да, такое. Никак нельзя убрать (или иначе оформить) эти readable/writeable? Спасибо

Для ранних С++ тоже можно написать решение, только кода будет значительно больше, в основном из-за "_Arguments ... args". Сделать основу?

Совсем от readable/writable избавиться не получится.

Либо придется следить за const так

Код
C++ (Qt)
ImplicitWrapper< Test > mutable_value = ImplicitWrapper< Test >::make();
mutable_value->method(); // всегда mutable метод
 
ImplicitWrapper< const Test > const_value = mutable_value;
const_value->method(); // всегда cosnt
 

Либо так

Код
C++ (Qt)
// value не предоставляет доступ к Test
ImplicitWrapper< Test > value = ImplicitWrapper< Test >::make();
 
WriteAccessor< Test > writer( value );
writer->method(); // всегда mutable метод
writer.value().method(); // всегда mutable метод
 
ReadAccessor< Test > reader( value );
reader->method(); // всегда const метод
reader.value().method(); // всегда const метод
 

Либо так

Код
C++ (Qt)
// value не предоставляет доступ к Test
ImplicitWrapper< Test > value = ImplicitWrapper< Test >::make();
 
writable( value ).method(); // всегда mutable метод
readable( value ).method(); // всегда const метод
 

Либо как изначально

Код
C++ (Qt)
ImplicitWrapper< Test > value = ImplicitWrapper< Test >::make();
 
value.writable().method(); // всегда mutable метод
value.readable().method(); // всегда const метод
 

Выберете один из. Мне больше нравится третий, так как этот вариант легче всего переопределить под произвольный тип (как std::begin/std::end). Но это мое субъективное мнение.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 07, 2017, 14:58
Для QSharedPointer и более ранних С++

Код
C++ (Qt)
#include <memory>
#include <QSharedPointer>
 
class AbstractHolder
{
public:
   typedef QSharedPointer< AbstractHolder > SharedAbstractHolder;
 
public:
   virtual ~AbstractHolder () {}
   virtual SharedAbstractHolder clone () const = 0;
};
 
template < typename _Type >
QSharedPointer< _Type > makeShared()
{
   return QSharedPointer< _Type >( new _Type );
}
 
template < typename _Type, typename _Arg0 >
QSharedPointer< _Type > makeShared( const _Arg0 & arg0 )
{
   return QSharedPointer< _Type >( new _Type( arg0 ) );
}
 
// etc ... _Arg1, _Arg2 ...
 
template < typename _Type >
class Holder
   : public AbstractHolder
{
   typedef Holder< _Type > ThisType;
   typedef AbstractHolder ParentType;
 
public:
   typedef _Type ValueType;
 
private:
   ValueType m_value;
 
public:
   Holder ()
   : m_value()
   {
   }
 
   template < typename _Arg0 >
   Holder ( const _Arg0 & arg0 )
   : m_value( arg0 )
   {
   }
 
   // etc ... _Arg1, _Arg2 ...
 
   const _Type & readable () const
   {
       return m_value;
   }
 
   _Type & writable ()
   {
       return m_value;
   }
 
   virtual SharedAbstractHolder clone () const
   {
       return makeShared< ThisType >( m_value );
   }
};
 
 
template < typename _Type >
class ImplicitWrapper
{
private:
   typedef ImplicitWrapper< _Type > ThisType;
   typedef Holder< _Type > HolderType;
   typedef QSharedPointer< AbstractHolder > SharedAbstractHolder;
 
   template < typename _OtherType >
   friend class ImplicitWrapper;
 
private:
   SharedAbstractHolder m_shared_holder;
 
private:
   ImplicitWrapper ( const SharedAbstractHolder & holder )
   : m_shared_holder( holder )
   {
   }
 
   void detach ()
   {
       // Hack!!! Qt4 protected, Qt5 private
       struct HackValue
       {
           struct Data
           {
               QBasicAtomicInt weakref;
               QBasicAtomicInt strongref;
           };
 
           AbstractHolder * m_type;
           Data * m_data;
       };
       HackValue * hack = reinterpret_cast< HackValue * >( &m_shared_holder );
 
       if ( hack->m_data->strongref > 1 )
           m_shared_holder = m_shared_holder->clone();
   }
 
public:
   ImplicitWrapper ()
   : m_shared_holder()
   {
   }
 
   template < typename _OtherType >
   ImplicitWrapper ( const ImplicitWrapper< _OtherType > & other )
   : m_shared_holder( other.m_shared_holder )
   {
       Q_ASSERT( !other.m_shared_holder
           || static_cast< _Type * >( const_cast< _OtherType * >( &other.readable() ) ) );
   }
 
   bool isNull () const
   {
       return !m_shared_holder;
   }
 
   const _Type & readable () const
   {
       return m_shared_holder.staticCast< HolderType >()->readable();
   }
 
   _Type & writable ()
   {
       detach();
       return m_shared_holder.staticCast< HolderType >()->writable();
   }
 
public:
   static ThisType make ()
   {
       return ThisType( makeShared< Holder< _Type > >() );
   }
 
   template < typename _Arg0 >
   static ThisType make ( const _Arg0 & arg0 )
   {
       return ThisType( makeShared< Holder< _Type > >( arg0 ) );
   }
 
   // etc ... _Arg1, _Arg2 ...
};
 
#include <iostream>
 
struct Test
{
   Test ()
   {
       std::cout << "Constructor of Test" << std::endl;
   }
 
   Test ( const Test & )
   {
       std::cout << "Copy of Test" << std::endl;
   }
 
   virtual ~Test ()
   {
       std::cout << "Destructor of Test" << std::endl;
   }
 
   virtual void method ()
   {
       std::cout << "Mutable method of Test" << std::endl;
   }
 
   virtual void method () const
   {
       std::cout << "Constant method of Test" << std::endl;
   }
};
 
struct DerivedTest
   : public Test
{
   DerivedTest ()
   {
       std::cout << "Constructor of DerivedTest" << std::endl;
   }
 
   DerivedTest ( const DerivedTest & other )
   : Test( other )
   {
       std::cout << "Copy of DerivedTest" << std::endl;
   }
 
   virtual ~DerivedTest ()
   {
       std::cout << "Destructor of DerivedTest" << std::endl;
   }
 
   virtual void method ()
   {
       std::cout << "Mutable method of DerivedTest" << std::endl;
   }
 
   virtual void method () const
   {
       std::cout << "Constant method of DerivedTest" << std::endl;
   }
};
 
struct OtherTest
{
   OtherTest ()
   {
       std::cout << "Constructor of OtherTest" << std::endl;
   }
 
   ~OtherTest ()
   {
       std::cout << "Destructor of OtherTest" << std::endl;
   }
 
   void method ()
   {
       std::cout << "Mutable method of OtherTest" << std::endl;
   }
 
   void method () const
   {
       std::cout << "Constant method of OtherTest" << std::endl;
   }
};
 
int main ( int, char ** )
{
   int test_number = 0;
   // OK
   {
       std::cout << "Test - " << (test_number++) << std::endl;
       ImplicitWrapper< Test > test_value = ImplicitWrapper< Test >::make();
       test_value.readable().method();
       test_value.writable().method();
   }
 
   // OK
   {
       std::cout << "Test - " << (test_number++) << std::endl;
       ImplicitWrapper< Test > test_value = ImplicitWrapper< DerivedTest >::make();
       test_value.readable().method();
       test_value.writable().method();
   }
 
   // OK
   {
       std::cout << "Test - " << (test_number++) << std::endl;
       ImplicitWrapper< const Test > test_value = ImplicitWrapper< DerivedTest >::make();
       test_value.readable().method();
       test_value.writable().method();
   }
 
   // ERROR
//    {
//    std::cout << "Test - " << (test_number++) << std::endl;
//        ImplicitWrapper< Test > test_value = ImplicitWrapper< OtherTest >::make();
//        test_value.readable().method();
//        test_value.writable().method();
//    }
 
   // OK
   {
       std::cout << "Test - " << (test_number++) << std::endl;
       ImplicitWrapper< DerivedTest > first_value = ImplicitWrapper< DerivedTest >::make();
       ImplicitWrapper< Test > second_value = first_value;
       second_value.readable().method();   // not detached
       second_value.writable().method();     // detached
   }
 
   // OK
   {
       std::cout << "Test - " << (test_number++) << std::endl;
       ImplicitWrapper< Test > second_value = ImplicitWrapper< DerivedTest >::make( DerivedTest() );
       second_value.readable().method();
       second_value.writable().method();
   }
 
   return 0;
}
 


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 08, 2017, 08:48
...в основном из-за "_Arguments ... args". Сделать основу?
Спасибо, не нужно, эти "вариадики" меня так пугают...

А вот такая (экспериментальная) мысль - а не задействовать ли и здесь weak_ptr (вероятно его аналог). Guard - ценная возможность, ну может detach при его создании...


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 08, 2017, 15:54
А вот такая (экспериментальная) мысль - а не задействовать ли и здесь weak_ptr (вероятно его аналог). Guard - ценная возможность, ну может detach при его создании...

Implicit shared обертка реализует композитную уникальную ассоциацию (composite) уникальное представление экземпляра объекта с помощью механизма "ленивых вычислений", когда вычисления производятся только при необходимости. В данном контексте к вычислениям относится необходимость копирования данных объекта при их модификации. Механизм "ленивых вычислений" в данном случае реализуют с помощью ассоциации обобщенной агрегации (shared), однако сам объект, как мы раннее выяснили, реализует композитную уникальную ассоциацию (composite) сама Implicit shared обертка представляет уникальный экземпляр объекта, как если бы была реализована ассоциация уникальной композиции (composite) .

Так как композитная ассоциация уникальное представление экземпляра объекта оберткой реализуется посредством обобщенной агрегации, то такой случай и называется неявное обобщение (Implicit shared).

Касаясь вопроса применения weak_ptr во внутренней реализации обертки, то weak_ptr не реализует агрегацию в принципе - ни композитную, ни обобщенную. weak_ptr реализует ассоциативную связь с возможностью продления времени жизни экземпляра объекта, поэтому в данном месте неприменим.

Необходимо отметить, что для экземпляров объектов под управлением Implicit shared не существует возможности сослаться любым другим способом, так как они могут быть клонированы в любой момент. Однако имеется возможность ссылки на саму Implicit shared обертку.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ViTech от Февраль 08, 2017, 17:27
Я бы не стал смешивать ассоциации и Implicit shared. По мне, copy-on-write - это просто техника оптимизации хранения и копирования данных объекта, его внутренние проблемы, и не более. Есть ли в объекте cow, нет ли, на логику создания/удаления, владения, связей между объектами, логику модели это никакого влияния оказывать не должно.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 08, 2017, 17:42
Я бы не стал смешивать ассоциации и Implicit shared. По мне, copy-on-write - это просто техника оптимизации хранения и копирования данных объекта, его внутренние проблемы, и не более. Есть ли в объекте cow, нет ли, на логику создания/удаления, владения, связей между объектами, логику модели это никакого влияния оказывать не должно.

Да, напрямую не стоит смешивать.
Я имел всего лишь в виду, что Implicit shared обертка представляет сам объект, как уникальный экземпляр, в то время как он на самом деле обобщенный. А ассоциации здесь относятся к внутренней архитектуре самой обертки, как и весь предыдущий мой пост о возможности применения внутри weak_ptr. Поправлю помарки).




Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 08, 2017, 18:58
По мне, copy-on-write - это просто техника оптимизации хранения и копирования данных объекта, его внутренние проблемы, и не более. Есть ли в объекте cow, нет ли, на логику создания/удаления, владения, связей между объектами, логику модели это никакого влияния оказывать не должно.
Категорически согласен! Корова может быть пожертвована в любой момент, пример
Код:
QVector<int> vec;
...
int test = vec[0];   // detach (хотя никакой необходимости не было)
Я бы не стал смешивать ассоциации и Implicit shared.
Но почему совершенно противоположный вывод ???  :)

Касаясь вопроса применения weak_ptr во внутренней реализации обертки, то weak_ptr не реализует агрегацию в принципе - ни композитную, ни обобщенную. weak_ptr реализует ассоциативную связь с возможностью продления времени жизни экземпляра объекта, поэтому в данном месте неприменим.
Мне кажется Вы слишком увлеклись абстракцией :) Есть блочок памяти в котором сидят счетчики и (возможно) хранимый объект. Этот блочок живет пока хотя бы 1 из счетчиков ненулевой. Weak имеет к нему доступ так же как и шаред, просто weak не препятствует удалению объекта. Почему Вы считаете его чем-то принципиально иным?

Не очень понял про "агрегацию" и "ассоциацию", если нетрудно поясните что значат эти термины в данном контексте. Спасибо


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: ssoft от Февраль 08, 2017, 20:47
Не очень понял про "агрегацию" и "ассоциацию", если нетрудно поясните что значат эти термины в данном контексте. Спасибо

Это понятия модели ООП.
Ассоциация - это понятие означающее, что экземпляры одного класса связаны с экземплярами другого класса. Также вводится понятие связь (link), как экземпляра ассоциации, которая реализуется в виде, включающем понятие полюсов. Полюсы могут являться частью сущностей, участвующих в ассоциации. Если не вдаваться в подробности, то связи (их полюсы) реализуются всяческими указателями, ссылками или вычисляются runtime.

Ассоциации бывают бинарными, и т.д. N-нарными, в зависимости от количества участвующих сущностей. Чаще всего мы имеем дело с бинарными ассоциациями. Одним из частных случаев бинарной ассоциации является отношение типа "часть ‒ целое", такие ассоциации имеют название агрегации. В такой ассоциации целым (агрегатором) по отношению к части может быть только одна сущность (правила подобны отношению наследования). Целое может агрегировать часть индивидуально (composite) или совместно (shared). Первый случай часто называют композицией. Отношение "часть - целое" регламентирует удаление части вместе с целым (по крайне мере в композиции).

Удобно совместить контроль времени жизни экземпляра объекта с экземпляром полюса, реализующим ассоциативную связь агрегации. Другого вида ассоциативные связи, по моему, логически несовместимы с контролем времени жизни. Хорошо иллюстрирует ассоциативную связь агрегации отношение parent - child, когда child "знает", кто его parent. parent должен обеспечить уникальное владение своими child, а child ссылаться на своего parent.

weak_ptr не реализует полюс ассоциативной связи агрегации со стороны целого (так как не управляет временем жизни экземпляра) , хотя может реализовывать полюс ассоциативной связи агрегации со стороны части.
Wrapper является целым по отношению к хранимому объекту, таким образом внутреннее представление должно реализовывать полюс ассоциации со стороны целого в любом доступном виде.


Название: Re: cow_ptr (полиморфная шара)?
Отправлено: Igors от Февраль 09, 2017, 12:23
Ассоциация - это понятие означающее..
Не все, но кое-что понял. Спасибо за разъяснения.

Насчет аналога weak_ptr.

Посмотрим что с "продлением жизни". Допустим если объект "жив" - увеличиваем число ссылок на него создавая еще один wrapper (cow_ptr). Однако, в отличие от шаред, мы согласились с созданием копии (пусть копирование состоится и не сразу). И можем с копией и остаться, т.е. по сути ничего не продлеваем.

Можно конечно действовать по образцу QPointer, так мы получим raw указатель если живой. Что легко может стать источником ошибок. Напр теперь уже нельзя из него делать wrapper. Ну может ограничить аналог weak методами isNull и константным ->

Мда, как-то становится неуютно когда нет знакомых вещей  :)