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

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

Страниц: [1] 2 3 ... 5   Вниз
  Печать  
Автор Тема: SharedHash/Set  (Прочитано 48524 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Май 13, 2019, 06:51 »

Добрый день

Цель: используя шаред_птр, иметь только уникальные экземпляры класса. Грубо говоря, шарить все, тотально. Так вроде бы шаред_птр для этого и предназначен?  Не совсем. Когда один шаред присваивается другому - все прекрасно. Но когда мы создаем его с нуля, напр данные читаются из файла, уникальность не обеспечивается
Код
C++ (Qt)
m_name = QSharedPointer<std::string> (new std::string("abc"));
// а если "abc" уже есть?
А задействовать QHash/QSet/QCache так просто не выходит т.к. все они владеют данными сами и с шаред не дружат.

Предлагаемый велик по сути имеет один метод Put для создания шаред
Код
C++ (Qt)
CSharedSet<std::string> theSet;
...
m_name = theSet.Put(new std::string("abc"));
Если "abc" уже есть, эти данные будут шариться, а новая строка удалена. Аргументом Put должен быть голый указатель созданный с помощью new, theSet, как говорится, "takes ownership". В случае CSharedSet шаред должен быть объявлен указателем на константу,  т.к. сами данные - ключ и изменены быть не могут
Код
C++ (Qt)
QSharedPointer<const std::string> m_name;
А если хотим менять, то нужно сделать копию используя new, изменить ее и перезарядить тем же Put, напр
Код
C++ (Qt)
std::string * temp = new std::string(*m_name.data());
*temp += " edit";
m_name = theSet.Put(temp);
Что вообще-то не очень красиво, но приемлемо. В случае CSharedHash этой мороки нет, т.к. ключ отдельно, сами решаем менять данные для всех шарящих или как.

Сам CSharedHash/Set данными не владеет и может быть безболезненно удален. В остальном логика шаред никак не меняется, ну разве что кастомный deleter нельзя, он уже занят. Да, и там со статиком не очень красиво, как лучше?

Это все, попинайте, ну или расскажите о чудесных классах которые "уже давно написаны"  Улыбающийся
« Последнее редактирование: Май 19, 2019, 10:45 от Igors » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #1 : Май 14, 2019, 12:14 »

А что мешало сделать value-based обертку с использованием QExplicilySharedDataPointer и заюзать обычный QSet?

Проблему аллокаций вы так и не решили - вы экономите количество памяти, но не количество аллокаций. Имхо, задача решена только на половину=)

ЗЫ: QESDP проблему аллокаций также не решает но позволяет не писать свой велосипед=)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Май 14, 2019, 13:11 »

А что мешало сделать value-based обертку с использованием QExplicilySharedDataPointer и заюзать обычный QSet?
Никогда не юзал Q(Explicitly)SharedDataPointer, только читал, идея кажется понятной. Не вижу разницы со стандартным Qt имплисит классом, напр QString, все так же не удается раскрутиться с hash/set. Если я туда посажу QString (QSharedDataPointer,  QExplicitlySharedDataPointer), то кто (или когда, или каким образом) удалит данные (ту же QString)?

Проблему аллокаций вы так и не решили - вы экономите количество памяти, но не количество аллокаций. Имхо, задача решена только на половину=)

ЗЫ: QESDP проблему аллокаций также не решает но позволяет не писать свой велосипед=)
Поясните в чем разница между этими понятиями (память/аллокация)? Кстати экономия памяти сейчас мало интересует, больше дорогие расчеты
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #3 : Май 14, 2019, 14:50 »

Никогда не юзал Q(Explicitly)SharedDataPointer, только читал, идея кажется понятной. Не вижу разницы со стандартным Qt имплисит классом, напр QString, все так же не удается раскрутиться с hash/set. Если я туда посажу QString (QSharedDataPointer,  QExplicitlySharedDataPointer), то кто (или когда, или каким образом) удалит данные (ту же QString)?

А, я не смотрел реализацию и не видел, что кэш данными не владеет. Да, Q(E)SDP тут не поможет.
Разница между QESDP и QSDP что первый не детачит в непонятных местах и оставляет это на разработчика класса.

Что вам надо сдеать, это вместо метода put сделать мутод getOrCreate - это позволит избежать ненужной аллокации.
Код:
template <class Key, class Val, class Args...>
std::shared_pointer<Val> getOrCreate(Key key, Args... args)
{
    const auto it = mHash.find(key);
    if (it != mHash.end()) {
        const auto result = it->second.lock();
        if (result) // нашли в кэше
             return result;
    }
    auto data = std::make_shared<Val>(std::forward(args));
    mHash.insert(key, data);
    return data;
}

Поясните в чем разница между этими понятиями (память/аллокация)? Кстати экономия памяти сейчас мало интересует, больше дорогие расчеты


Есть потребление памяти - это сколько программа занимает места в памяти вот прямо сейчас (в момент времени Х).
А есть количество аллокаций и общий объем аллокаций - это сколько памяти программа аллоцировала за всё время работы.
Например:
Код:
   for (int i = 0; i < 10; ++i) {
        std::string hello("hello");
    }
Перед циклом: потребление памяти 0 байт, количество аллокаций - 0, объем аллокаций 0.
Во время цикла - потребление памяти 6 байт (на 1 строку), количество аллокаций - i, объем аллокаций i*6.
После цикла - потребление памяти 0 байт, количество аллокаций - 10, объем аллокаций 10*6.
То есть в пике мы потребили 6 байт, но при этом нааллоцировали/наудаляли на 60.

Парные аллокации/удаления влияют в основном на скорость работы программы. На общее потребление памяти они тоже влияют, но опосредованно - за счет фрагментации программа может запрашивать новые страницы у ОС. А может и не запрашивать, тут как повезет, с фрагментацией сложно бороться.
Непарные аллокации, помимо времени, еще и требуют всё новой и новой памяти.
Шаредные данные решают проблему аллокации при копировании объекта (самый частый юзкейз до с++11). Начиная с 11х плюсов можно вообще побанить копирование и делать move-only объекты, которые "трансформируются" в новое состояние вместо изменения копии старого, но это не ваш случай.

В вашем случае надо понять, как достать объект из кэша так, чтобы не аллоцировать новый объект. Пример с Args... тоже решение частичное - он хорош когда мы создаем новый объект один-в-один как на старый, а когда мы читаем объект из файла, что делать?...
« Последнее редактирование: Май 14, 2019, 14:54 от Авварон » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Май 15, 2019, 06:00 »

Что вам надо сдеать, это вместо метода put сделать мутод getOrCreate - это позволит избежать ненужной аллокации.
Не считая наворотов Args так оно и сделано. Загвоздка в том что когда данные автоматом убьются - они должны быть (тоже автоматом) вычищены из хеша, в основном все посвящено этому.
В вашем случае надо понять, как достать объект из кэша так, чтобы не аллоцировать новый объект. Пример с Args... тоже решение частичное - он хорош когда мы создаем новый объект один-в-один как на старый, а когда мы читаем объект из файла, что делать?...
Ну в случае Hash (имеется ключ) можно провериться Get. А в случае Set думается решения объективно нет, сравниваются сами данные, а значит вторую копию надо иметь.

Вообще с фрагментацией и.т.п. по-моему явный перегиб. Применение гораздо прозаичнее. Те же текстуры что давеча упоминал, интенсивно шарятся. Вот мне надо (всего-навсего) распечатать какие текстуры сейчас загружены (ключ - имя файла), любой тест начнется с этого. И выясняется что, при всей безумной  крутизне современных средств, всяких мувов, форвардов и хз чего, какого-то простого, удобного решения не видно Плачущий Как бы срабатывает обратная сторона шаред_птр - да, грохнет автоматом - хорошо, но вот живы данные или как - не получить.

Возможен и др подход - забить на шаред_птр и считать ссылки самому. Тогда с помещением в hash/set нет проблем, но ценой общности - придется ковырять каждый используемый класс.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 574


Просмотр профиля
« Ответ #5 : Май 15, 2019, 07:59 »

Не считая наворотов Args так оно и сделано. Загвоздка в том что когда данные автоматом убьются - они должны быть (тоже автоматом) вычищены из хеша, в основном все посвящено этому.
А нельзя хранить в хеше в качестве значения weak_ptr и использовать deleter, который удалит этот weak из хеша при удалении объекта?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Май 15, 2019, 12:08 »

А нельзя хранить в хеше в качестве значения weak_ptr и использовать deleter, который удалит этот weak из хеша при удалении объекта?
Вы бы исходники пролистали - ведь так там и сделано Улыбающийся только в классах Qt. Тут, правда, пара мелких проблемок

а) хеш может быть удален/очищен - ну не беда, решается еще одним "наблюдающим" weak'ом (mLive)

б) а вот как передать итератор в deleter - не сообразил, сделал дубовым статиком, что, конечно, не есть хорошо. Что предложите?

Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #7 : Май 15, 2019, 16:07 »

Кстати, не советую юзать кутешый шаред поинтер, у него нет аналога std::make_shared, который делает одну аллокацию, вместо двух.

Ну а так, передавайте ключ в deleter вместо итератора, в чем проблема?
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #8 : Май 15, 2019, 17:03 »

Кстати, не советую юзать кутешый шаред поинтер, у него нет аналога std::make_shared, который делает одну аллокацию, вместо двух.

Аналог есть, QSharedPointer::create() называется. Но, не смотря на это, я тоже не советую его использовать.
Записан

Пока сам не сделаешь...
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #9 : Май 15, 2019, 17:15 »


Аналог есть, QSharedPointer::create() называется.

И правда. Ох уж этот NIH синдром...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Май 16, 2019, 09:36 »

Ну а так, передавайте ключ в deleter вместо итератора, в чем проблема?
А для Set что вместо ключа? Да и для Hash - как минимум неаккуратно, ключ может быть весьма развесистым/расходным.

Кстати, не советую юзать кутешый шаред поинтер, у него нет аналога std::make_shared, который делает одну аллокацию, вместо двух.
Как у Вас все просто: тут есть, а там нет - ну стало быть этот лучше Улыбающийся А по-моему уже само использование std:: ясно говорит: ни на какую "заточку" по памяти и/или скорости мы не претендуем. Зато выигрываем в скорости/легкости написания, ну в этом есть смысл. Да и чисто объективно тот make_shared - палка о двух концах, ведь при этом удаленный объект занимает память пока есть хоть один weak.

Если же нужно "выжать все" и фрагментация реально волнует, то нужно считать ссылки руками, интрузивно. Да, хлопот больше, но быстрее будет. Ну это уже когда счет идет на мульены (как напр в задачах рендера) .

Аналог есть, QSharedPointer::create() называется. Но, не смотря на это, я тоже не советую его использовать.
Уже не первый раз наблюдаю такое "поджимание губок" при обсуждении Qt классов, мол, да это (ветхое) старье и.т.п. Можно узнать на чем основывается это мнение? Мелкие неудобства там и сям? (напр QSharedPointer не имеет доступа к счетчику ссылок, а надо). Что еще? Дешевые std-шные понты? Или чей-то заказ отрабатываем?  Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #11 : Май 16, 2019, 11:44 »

Аналог есть, QSharedPointer::create() называется. Но, не смотря на это, я тоже не советую его использовать.
Уже не первый раз наблюдаю такое "поджимание губок" при обсуждении Qt классов, мол, да это (ветхое) старье и.т.п. Можно узнать на чем основывается это мнение? Мелкие неудобства там и сям? (напр QSharedPointer не имеет доступа к счетчику ссылок, а надо). Что еще? Дешевые std-шные понты? Или чей-то заказ отрабатываем?  Улыбающийся

Да Вы-то пользуйтесь на здоровье Улыбающийся. Я больше для других читателей форума писал.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Май 16, 2019, 12:10 »

Я больше для других читателей форума писал.
Ну так вот Вам и карты в руки - развейте мысль(и) покажите как (или чем) std аналоги круче - и намного! А то пока выглядит как просто стремление "следовать моде" которому, увы, подвержены не только женщины. 

Да Вы-то пользуйтесь на здоровье Улыбающийся.
Думается Вы напрасно уделяете std столько времени и сил - эта штука всегда была и будет "ширпотребом", чего-то с ней достичь невозможно. Игнорировать ее конечно не стоит, но так "упиваться" синтаксическим сахаром ни к чему. Ну это тоже больше для других  Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



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

Ну так вот Вам и карты в руки - развейте мысль(и) покажите как (или чем) std аналоги круче - и намного! А то пока выглядит как просто стремление "следовать моде" которому, увы, подвержены не только женщины.

Про недостатки Qt я на этом форуме достаточно писал. Если очень интересно - поищите и почитайте.

Если не отходить от темы, я бы поставил вопрос по другому: какие преимущества есть у QSharedPointer, чтобы пользоваться им, а не std::shared_ptr? QSharedPointer был актуален, пока в стандартной библиотеке С++ не было аналога (до С++11). Но сейчас std::shared_ptr должен поставляться с любым нормальным компилятором, а для QSharedPointer нужно Qt устанавливать. И даже если работать в рамках Qt, чем QSharedPointer превосходит std::shared_ptr?
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Май 16, 2019, 14:06 »

Про недостатки Qt я на этом форуме достаточно писал. Если очень интересно - поищите и почитайте.
Так Вы и в этой теме так же писали, мол, "не советую". А почему? Чем руководствуется советчик? Хз, наверное такому надо просто верить на слово Улыбающийся

, я бы поставил вопрос по другому: какие преимущества есть у QSharedPointer, чтобы пользоваться им, а не std::shared_ptr? QSharedPointer был актуален, пока в стандартной библиотеке С++ не было аналога (до С++11). Но сейчас std::shared_ptr должен поставляться с любым нормальным компилятором, а для QSharedPointer нужно Qt устанавливать. И даже если работать в рамках Qt, чем QSharedPointer превосходит std::shared_ptr?
Да может и ничем не превосходит, может std::shared_ptr даже чуть больше имеет, что совершенно нормально, новая вещь учла предыдущий опыт. НО - достаточное ли это основание чтобы менять имеющийся код? Или хотя бы избегать QSharedPointer в новом коде? Считаю что совершенно НЕТ. Не видно явных, принципиальных плюсов (а их нет) - нечего тратить время на изучение "чуть лучшего".

Если не отходить от темы..
А тема совсем не от том Улыбающийся И в теме неважно, тот шаред или этот. Важно другое, но оно Вас не интересует - понимаю, поглощены изучением std...
Записан
Страниц: [1] 2 3 ... 5   Вверх
  Печать  
 
Перейти в:  


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