Russian Qt Forum
Апрель 25, 2024, 22:33 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Указатель/ссылка на содержимое QVariant  (Прочитано 12333 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Февраль 13, 2019, 12:23 »

QVariant шарится))), и об этом явно написано в документации "тыц ссылкой", где приведена таблица классов Qt, использующих implicit shared.
Не всему надо верить, на заборе тоже много чего написано  Улыбающийся Откройте переменную типа QVariant в отладчике - никаких "своих" счетчиков ссылок она не имеет.

QVariant может хранить практически любой copyable тип данных, и совершенно не догадывается о том какой он, с имплисит шарой или без.
Очень даже "догадывается", см напр флажок is_shared или хотя бы фрагмент кода что выше привел ViTech. Когда хранимый тип имеет имплисит шару, содержимое не копируется. Причем это почему-то поддерживается самим QVariant'ом (неясно зачем?). Но если, как в стартовом посте, хранимый тип std::vector - то никакой шары нет, и бедняга вектор гоняется туда-сюда всякий раз.  

Технических особенностей, почему бы не предоставить доступ к внутреннему содержимому, как, например, для QByteArray, никаких нет. Для std::any имеется std::any_cast< MyType & >.
Из-за отсутствия таких методов, QVariant постоянно использует копирование внутренних данных (fromValue/value), что приводит не редко к существенным потерям производительности.
Это я уже осознал, предлагаю вернуться к теме: как лучше сделать "шареный вариант"?

Сам тип, конечно , достаточно будет заменить на std::any) (но только с С++17).
Но там еще обвязка по динамической работе с типами и регистрации произвольной функциональности (кастование и преобразование типов, фабричные методы, сериализация и определенная пользователем любая другая).
Согласен, QVariant выглядит гораздо солиднее чем легковесный std::any.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #16 : Февраль 13, 2019, 13:49 »

Не всему надо верить, на заборе тоже много чего написано  Улыбающийся Откройте переменную типа QVariant в отладчике - никаких "своих" счетчиков ссылок она не имеет.

Да ладно? ) А здесь?

Код
C++ (Qt)
   struct PrivateShared
   {
       inline PrivateShared(void *v) : ptr(v), ref(1) { }
       void *ptr;
       QAtomicInt ref;
   };
 

Не шарятся только данные влезающие по размеру в

Код
C++ (Qt)
       union Data
       {
           char c;
           uchar uc;
           short s;
           signed char sc;
           ushort us;
           int i;
           uint u;
           long l;
           ulong ul;
           bool b;
           double d;
           float f;
           qreal real;
           qlonglong ll;
           qulonglong ull;
           QObject *o;
           void *ptr;
           PrivateShared *shared;
       } data;
 

Остальные, в том числе и ::std::vector, попадают в секцию else, где d->is_shared = true

Код
C++ (Qt)
static void customConstruct(QVariant::Private *d, const void *copy)
{
   const QMetaType type(d->type);
   const uint size = type.sizeOf();
   if (!size) {
       qWarning("Trying to construct an instance of an invalid type, type id: %i", d->type);
       d->type = QVariant::Invalid;
       return;
   }
 
   // this logic should match with QVariantIntegrator::CanUseInternalSpace
   if (size <= sizeof(QVariant::Private::Data)
           && (type.flags() & (QMetaType::MovableType | QMetaType::IsEnumeration))) {
       type.construct(&d->data.ptr, copy);
       d->is_shared = false;
   } else {
       void *ptr = type.create(copy);
       d->is_shared = true;
       d->data.shared = new QVariant::PrivateShared(ptr);
   }
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Февраль 13, 2019, 14:38 »

Остальные, в том числе и ::std::vector, попадают в секцию else, где d->is_shared = true
Да, Вы правы
Код
C++ (Qt)
QVariant v;
...
QVariant v2 = v;  // тут копирования std::vector не будет
Интересная возможность, не знал. Но увы, это никак не решает проблемы с доступом к содержимому
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #18 : Февраль 13, 2019, 15:05 »

Для пользовательских типов можно сделать так (со всеми оговорками про имплисит шару)

Код
C++ (Qt)
#include <QVariant>
#include <vector>
 
template < typename _Type >
inline _Type & qUserVariantAccess ( QVariant & value )
{
   Q_ASSERT( qMetaTypeId< _Type >() == value.userType() );
   return *reinterpret_cast< _Type *>( value.data() );
}
 
template < typename _Type >
inline const _Type & qUserVariantAccess ( const QVariant & value )
{
   Q_ASSERT( qMetaTypeId< _Type >() == value.userType() );
   return *reinterpret_cast< _Type *>( value.constData() );
}
 
int main ( int, char ** )
{
   QVariant variant;
 
   variant.setValue( ::std::vector< int >() );
   qUserVariantAccess< ::std::vector< int > >( variant ).push_back( 3 );
   qUserVariantAccess< ::std::vector< int > >( variant ).push_back( 1 );
   qUserVariantAccess< ::std::vector< int > >( variant ).push_back( 2 );
 
   return 0;
}
 
« Последнее редактирование: Февраль 13, 2019, 16:56 от ssoft » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #19 : Февраль 13, 2019, 16:24 »

Для пользовательских типов можно сделать так (со всеми оговорками про имплисит шару)
Нелегальщина, но чертовски заманчиво, подумаю. Изменит все ссылающиеся QVariant что здесь и нужно. Хорошо, а как сделать копию данных (не зная конкретного типа)?
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #20 : Февраль 13, 2019, 17:51 »

Код
C++ (Qt)
QVariant v;
...
QVariant v2 = v;
Интересная возможность, не знал. Но увы, это никак не решает проблемы с доступом к содержимому

Тут копирования не будет, но при попытке изменить данные, похоже, скопируется. В QVariant::data() выполняется detach(), соответственно в qUserVariantAccess(мутабельном) тоже детачнется.

Код
C++ (Qt)
template < typename _Type >
inline const _Type & qUserVariantAccess ( const QVariant & value )
{
   Q_ASSERT( qMetaTypeId< _Type >() == value.userType() );
   return *reinterpret_cast< _Type *>( value.constData() );
}
И всё равно const'а не хватает Подмигивающий.
Записан

Пока сам не сделаешь...
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #21 : Февраль 13, 2019, 21:53 »

Код
C++ (Qt)
template < typename _Type >
inline _Type & qUserVariantAccess ( QVariant & value )
{
   Q_ASSERT( qMetaTypeId< _Type >() == value.userType() );
   return *reinterpret_cast< _Type * >( value.data() );
}
 
template < typename _Type >
inline const _Type & qUserVariantAccess ( const QVariant & value )
{
   Q_ASSERT( qMetaTypeId< _Type >() == value.userType() );
   return *reinterpret_cast< const _Type * >( value.constData() );
}
 
template < typename _Type >
inline _Type & qUserVariantSharedAccess ( QVariant & value )
{
   Q_ASSERT( qMetaTypeId< _Type >() == value.userType() );
   return *const_cast< _Type * >( reinterpret_cast< const _Type * >( value.constData() ) );
}
 

Последний осуществляет доступ без detach.

Нелегальщина, но чертовски заманчиво, подумаю. Изменит все ссылающиеся QVariant что здесь и нужно. Хорошо, а как сделать копию данных (не зная конкретного типа)?

Каких-то хаков здесь нет, так что вполне легально.
А копия создается автоматически при вызове любого неконстантного метода.

Код
C++ (Qt)
QVariant v1;
...
QVariant v2 = v1; // shared - v2 идентичен v1
v2.data(); // detached copy - v2 и v1 разные копии
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #22 : Февраль 14, 2019, 04:54 »

Каких-то хаков здесь нет, так что вполне легально.
Ну все-таки методы data и constData не документированы
А копия создается автоматически при вызове любого неконстантного метода.
Да, все оказалось очень просто, спасибо
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.288 секунд. Запросов: 22.