Название: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 11, 2019, 13:11 Добрый день
Пример: в QVariant хранится std::vector (ну конечно зарегистировался Q_DECLARE_METATYPE). Теперь я хочу добавлять/удалять/менять эл-ты этого вектора. Не нашел как получить указатель или ссылку на данные хранимые в QVariant. Выходит всякий раз нужно перезаливать весь вектор :'( Это нормально или я плохо искал? Если нормально, то каковы мотивы такого ограничения? Спасибо Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Авварон от Февраль 11, 2019, 13:53 Да, это нормально, в мире без исключений метод, возвращающий ссылку, не может вернуть ошибку, если запрошенный тип не совпадает с тем, что реально лежит в QVariant. Только покрашить приложение с std::terminate.
Ну и о5 же всегда можно положить шаред_птр на вектор=) Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 11, 2019, 15:38 Ну и о5 же всегда можно положить шаред_птр на вектор=) Хорошо, пример: вот есть член какого-то класса которыйа) шарится б) может иметь содержимое разных типов Как "давить эти 2 окурка одновременно" ? Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Авварон от Февраль 11, 2019, 15:54 шаред_птр на вариант? ссылка на вариант?
Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 11, 2019, 19:55 QVariant имеет implicit shared реализацию, как в прочем QByteArray, QString, QList и т.п. а это значит, что хранить ссылки и указатели на внутренние данные - это бомба с замедленным действием. В любой момент внутреннее значение может стать другим после неявной операции detach. Такими ссылками нужно пользоваться ооочень аккуратно.
Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 12, 2019, 10:53 QVariant имеет implicit shared реализацию, как в прочем QByteArray, QString, QList и т.п. По-моему никакой имплисит шары сам QVariant не имеет, это 12 байт, 8 для хранения данных (напрямую или указатель) + тип по которому спрыгивает на базовый класс с виртуалами, Используется тот же паттерн что и в boost::any (и вероятно std::any), только базовый класс "один на тип", отсюда необходимость регистрировать.а это значит, что хранить ссылки и указатели на внутренние данные - это бомба с замедленным действием. В любой момент внутреннее значение может стать другим после неявной операции detach. Такими ссылками нужно пользоваться ооочень аккуратно. Ну если внутри сидит имплист контейнер и брать константный указатель на его данные - то да. Но для QVariant нет вообще никакого "доступа к содержимому"шаред_птр на вариант? ссылка на вариант? По сути нужна очень простая вещь - шарить вариант. Хотел такКод И заряжать вариант нужным контейнером. Но доступа к эл-там контейнера нет, поэтому не годится. Сделать наоборот почему-то не допер :) Код Все вполне хорошо - и вариант есть и шарится. Не хватает одной вещи - сделать копию данных (в общем виде, не влезая в разборки с конкретными типами). Напр в первом случае это легко Код И каким бы ни было содержимое варианта - он скопируется корректно. А во втором случае получим еще один шаред ссылающийся на те же данные. Ну ладно, переживу сввитчами. Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 12, 2019, 12:35 QVariant имеет implicit shared реализацию, как в прочем QByteArray, QString, QList и т.п. По-моему никакой имплисит шары сам QVariant не имеет, это 12 байт, 8 для хранения данных (напрямую или указатель) + тип по которому спрыгивает на базовый класс с виртуалами, Используется тот же паттерн что и в boost::any (и вероятно std::any), только базовый класс "один на тип", отсюда необходимость регистрировать.Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 12, 2019, 13:34 https://doc.qt.io/qt-5/implicit-sharing.html Ну вот, докатились до "тыц ссылкой" :) Возможно Вы имели ввиду что QVariant понимает что хранит тип с имплисит шарой, но об этом речь не идет (std::vector). Сам по себе QVariant НЕ шаритсяНазвание: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 12, 2019, 16:12 https://doc.qt.io/qt-5/implicit-sharing.html Ну вот, докатились до "тыц ссылкой" :) Возможно Вы имели ввиду что QVariant понимает что хранит тип с имплисит шарой, но об этом речь не идет (std::vector). Сам по себе QVariant НЕ шаритсяQVariant может хранить практически любой copyable тип данных, и совершенно не догадывается о том какой он, с имплисит шарой или без. Технических особенностей, почему бы не предоставить доступ к внутреннему содержимому, как, например, для QByteArray, никаких нет. Для std::any имеется std::any_cast< MyType & >. Из-за отсутствия таких методов, QVariant постоянно использует копирование внутренних данных (fromValue/value), что приводит не редко к существенным потерям производительности. Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ViTech от Февраль 12, 2019, 16:50 Ну вот, докатились до "тыц ссылкой" :) Возможно Вы имели ввиду что QVariant понимает что хранит тип с имплисит шарой, но об этом речь не идет (std::vector). Сам по себе QVariant НЕ шарится QVariant шарится))), и об этом явно написано в документации "тыц ссылкой", где приведена таблица классов Qt, использующих implicit shared.Можно такой ссылкой (https://github.com/qt/qtbase/blob/fd88c152db0949e47613858a914a6ae4a825781d/src/corelib/kernel/qvariant.cpp#L2364) тыцнуть, и по коду выяснять, шарится там что-нибудь или нет :). Хотя может сегодня оно шарится, а завтра уже нет (реализация поменялась). В исходниках можно ещё метод data() заметить, который для внутреннего пользования. Но если очень хочется, то можно и попользовать (на свой страх и риск). Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 12, 2019, 21:42 Можно такой ссылкой (https://github.com/qt/qtbase/blob/fd88c152db0949e47613858a914a6ae4a825781d/src/corelib/kernel/qvariant.cpp#L2364) тыцнуть, и по коду выяснять ... В исходниках можно ещё метод data() заметить, который для внутреннего пользования. Но если очень хочется, то можно и попользовать (на свой страх и риск). Всегда поражала такая куча кода))). Более 5 тыс. строк :o Все можно сделать намного меньшими усилиями. Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Old от Февраль 12, 2019, 21:46 Всегда поражала такая куча кода))). Более 5 тыс. строк :o Все можно сделать намного меньшими усилиями. Легаси же. :)Сейчас можно, но когда закладывался QVariant шаблоны были в зачаточном состоянии. :) Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 13, 2019, 08:04 Всегда поражала такая куча кода))). Более 5 тыс. строк :o Все можно сделать намного меньшими усилиями. Легаси же. :)Сейчас можно, но когда закладывался QVariant шаблоны были в зачаточном состоянии. :) Обычно да). Но в данном случае не так. Из-за ограничений QVariant, пришлось реализовать собственный аналог ещё в 2009. Весь функционал Qt и даже больше (с сериализацией, имплисит шарой и преобразованием пользовательских типов друг в друга) уместился ~1000..1500 строк. Сейчас как раз подумываю о рефакторинге на новый стандарт). Наверное еще меньше получится). Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ViTech от Февраль 13, 2019, 11:16 Всегда поражала такая куча кода))). Более 5 тыс. строк :o Все можно сделать намного меньшими усилиями. Там документации примерно половина, и многовато возни со встроенными и своими кутешными типами. Обилие нешаблонных методов toSomeType() тоже свой вклад вносит :). Сейчас как раз подумываю о рефакторинге на новый стандарт). Наверное еще меньше получится). Рефакторинга вида: Код не будет достаточно? :) Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 13, 2019, 12:09 Рефакторинга вида: Код не будет достаточно? :) ;D ;D ;D Сам тип, конечно , достаточно будет заменить на std::any) (но только с С++17). Но там еще обвязка по динамической работе с типами и регистрации произвольной функциональности (кастование и преобразование типов, фабричные методы, сериализация и определенная пользователем любая другая). Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 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. Но там еще обвязка по динамической работе с типами и регистрации произвольной функциональности (кастование и преобразование типов, фабричные методы, сериализация и определенная пользователем любая другая). Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 13, 2019, 13:49 Не всему надо верить, на заборе тоже много чего написано :) Откройте переменную типа QVariant в отладчике - никаких "своих" счетчиков ссылок она не имеет. Да ладно? ) А здесь? Код
Не шарятся только данные влезающие по размеру в Код
Остальные, в том числе и ::std::vector, попадают в секцию else, где d->is_shared = true Код
Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 13, 2019, 14:38 Остальные, в том числе и ::std::vector, попадают в секцию else, где d->is_shared = true Да, Вы правыКод Интересная возможность, не знал. Но увы, это никак не решает проблемы с доступом к содержимому Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 13, 2019, 15:05 Для пользовательских типов можно сделать так (со всеми оговорками про имплисит шару)
Код
Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 13, 2019, 16:24 Для пользовательских типов можно сделать так (со всеми оговорками про имплисит шару) Нелегальщина, но чертовски заманчиво, подумаю. Изменит все ссылающиеся QVariant что здесь и нужно. Хорошо, а как сделать копию данных (не зная конкретного типа)? Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ViTech от Февраль 13, 2019, 17:51 Код Интересная возможность, не знал. Но увы, это никак не решает проблемы с доступом к содержимому Тут копирования не будет, но при попытке изменить данные, похоже, скопируется. В QVariant::data() (https://github.com/qt/qtbase/blob/fd88c152db0949e47613858a914a6ae4a825781d/src/corelib/kernel/qvariant.cpp#L4137) выполняется detach(), соответственно в qUserVariantAccess(мутабельном) тоже детачнется. Код
Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: ssoft от Февраль 13, 2019, 21:53 Код
Последний осуществляет доступ без detach. Нелегальщина, но чертовски заманчиво, подумаю. Изменит все ссылающиеся QVariant что здесь и нужно. Хорошо, а как сделать копию данных (не зная конкретного типа)? Каких-то хаков здесь нет, так что вполне легально. А копия создается автоматически при вызове любого неконстантного метода. Код
Название: Re: Указатель/ссылка на содержимое QVariant Отправлено: Igors от Февраль 14, 2019, 04:54 Каких-то хаков здесь нет, так что вполне легально. Ну все-таки методы data и constData не документированыА копия создается автоматически при вызове любого неконстантного метода. Да, все оказалось очень просто, спасибо |