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

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Октябрь 30, 2015, 07:43 »

Как то это напоминает implicit sharing, но странно реализованным.
Плохо соображаю под вечер, но не мультииндекс ли это?
Хмм.. не знаю. Задача простая

- клиент (объект с ключом Key1) хочет рисоваться. Он знает как себя сейчас рисовать (Key2). Надо найти подходящий кеш рисования по Key2 или создать новый. Разумеется неиспользуемые кеши должны удаляться. Как и в случае если клиент удален или выключен (в этот момент Key2 нет). Вот собственно и все.

Есть др решение, без мапов - пожалуйста, предлагайте.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #16 : Октябрь 30, 2015, 08:39 »

Все равно не очень понятно назначение этих мапов.
Вот класс клиента, он содержит указатель на кеш. Если клонировать клиента, то они с клоном будут разделять кеш. Если один из них, захочет поменять кеш, он всегда сможет присвоить указателю новый объект и если кеш перестанет быть нужным он удалиться.
Код
C++ (Qt)
class Client
{
public:
   void draw()
   {
       if( !m_cache )
       {
           m_cache = make_shared<DrawCache>();
           forming( m_cache );
       }
       paint( m_cache );
   }
 
private:
   shared_ptr<DrawCache> m_cache;
};
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Октябрь 30, 2015, 13:35 »

Все равно не очень понятно назначение этих мапов.
Вот класс клиента, он содержит указатель на кеш. Если клонировать клиента, то они с клоном будут разделять кеш. Если один из них, захочет поменять кеш, он всегда сможет присвоить указателю новый объект и если кеш перестанет быть нужным он удалиться.
Подходящий кеш может уже иметься на момент создания клиента или отрисовки
Он знает как себя сейчас рисовать (Key2). Надо найти подходящий кеш рисования по Key2 или создать новый
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #18 : Октябрь 30, 2015, 14:21 »

Может тогда одного мапа достаточно:
Код
C++ (Qt)
typedef implicit_sharing<cache> shared_cache;
typedef std::pair<shared_cache, shared_cache> pair_t;
 
std::map<key, pair_t> map;
 
shared_cache cacheA;
 
map[keyA] = make_pair(cacheA, cacheA);
...
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #19 : Октябрь 30, 2015, 14:31 »

Подходящий кеш может уже иметься на момент создания клиента или отрисовки
Т.е. это просто справочник известных кешей?

Вот набросал немного кода:
Код
C++ (Qt)
#include <memory>
#include <map>
#include <iostream>
 
using namespace std;
 
struct DrawCache
{
explicit DrawCache( int key2 ) : m_key2( key2 )
{
cout << "Contruct DrawCache = " << m_key2 << endl;
}
 
~DrawCache()
{
cout << "Destruct DrawCache = " << m_key2 << endl;
}
 
int m_key2;
};
 
typedef shared_ptr<DrawCache> DrawCachePtr;
 
class Client
{
public:
explicit Client( int key2 )
{
DrawCachePtr val = m_caches[ key2 ].lock();
if( !val )
{
val = make_shared<DrawCache>( key2 );
m_caches[ key2 ] = val;
}
setCache( val );
}
 
~Client()
{
setCache( DrawCachePtr() );
}
 
void changeCache( const Client &other )
{
setCache( other.m_cache );
}
 
void draw()
{
paint( m_cache );
}
 
static void dumpCaches()
{
cout << "-----------------------------------------------------" << endl;
for( const auto &entry : m_caches )
{
DrawCachePtr cache = entry.second.lock();
 
cout << "Cache key2 = " << entry.first << " -> value = " << cache << endl;
}
}
 
protected:
void setCache( const DrawCachePtr &cache )
{
// Если это последний указатель на данный кеш, удаляем его из справочника
if( m_cache && m_cache.unique() )
m_caches.erase( m_cache->m_key2 );
 
m_cache = cache;
}
 
void paint( const DrawCachePtr &/*cache*/ )
{
}
 
private:
DrawCachePtr m_cache;
 
static map<int, weak_ptr<DrawCache>> m_caches;
};
 
map<int, weak_ptr<DrawCache>> Client::m_caches;
 
int main( int, char ** )
{
{
Client::dumpCaches();
Client cli1( 1 );
Client::dumpCaches();
Client cli2( 1 );
Client::dumpCaches();
Client cli3( 2 );
Client::dumpCaches();
cli2.changeCache( cli3 );
Client::dumpCaches();
cli1.changeCache( cli3 );
Client::dumpCaches();
}
Client::dumpCaches();
 
return 0;
}
 

Цитировать
-----------------------------------------------------
Contruct DrawCache = 1
-----------------------------------------------------
Cache key2 = 1 -> value = 0x13bac70
-----------------------------------------------------
Cache key2 = 1 -> value = 0x13bac70
Contruct DrawCache = 2
-----------------------------------------------------
Cache key2 = 1 -> value = 0x13bac70
Cache key2 = 2 -> value = 0x13bacd0
-----------------------------------------------------
Cache key2 = 1 -> value = 0x13bac70
Cache key2 = 2 -> value = 0x13bacd0
Destruct DrawCache = 1
-----------------------------------------------------
Cache key2 = 2 -> value = 0x13bacd0
Destruct DrawCache = 2
-----------------------------------------------------
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #20 : Октябрь 30, 2015, 16:42 »

Может тогда одного мапа достаточно:
Код
C++ (Qt)
typedef implicit_sharing<cache> shared_cache;
typedef std::pair<shared_cache, shared_cache> pair_t;
 
std::map<key, pair_t> map;
 
shared_cache cacheA;
 
map[keyA] = make_pair(cacheA, cacheA);
...
 

Непонимающий Ничего не понял  Улыбающийся

Т.е. это просто справочник известных кешей?

Вот набросал немного кода:
Хранить шаред на кеш прямо в клиенте неудачно. Напр карта может не поддерживать кеши или потребовалось их все выключить, или один клиент может иметь 2 кеша. Вообще в подробности рисования клиента лучше не посвящать, пусть он только даст нужные рисованию данные. Вот и приходим к еще одной (первой) мапе, где Key1 - просто (неперемещаемый) адрес клиента (ну почти).
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #21 : Октябрь 30, 2015, 19:16 »

Хранить шаред на кеш прямо в клиенте неудачно.
Ну это спорно. Подмигивающий

Напр карта может не поддерживать кеши или потребовалось их все выключить, или один клиент может иметь 2 кеша.
Никаких проблем с этим нет. Можно объявить массив кешей, если он не нужен/не поддерживается не заполнять его. Можно сделать иерархию классов для разных клиентов: не поддерживает кеш, поддерживает кеш и т.д. Много всего можно придумать.

пусть он только даст нужные рисованию данные. Вот и приходим к еще одной (первой) мапе, где Key1 - просто (неперемещаемый) адрес клиента (ну почти).
Ok, давайте определимся, какие операции нужны с какими исходными данными?
DrawCachePtr Manager::newCache()
DrawCachePtr Manager::getCache( int keyClient )
void Manager::removeCache( Непонимающий )
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #22 : Октябрь 31, 2015, 02:55 »

Никаких проблем с этим нет. Можно объявить массив кешей, если он не нужен/не поддерживается не заполнять его. Можно сделать иерархию классов для разных клиентов: не поддерживает кеш, поддерживает кеш и т.д. Много всего можно придумать.
Конечно можно, но весь этот код начинает литься в клиента, а там он совершенно неуместен. Клиент не должен ничего знать от том кто и как его кеширует, это не его дело. Даже хранение Key2 в клиенте плохо, т.к. Key2 это большой набор данных с массой подробностей рисования. Именно на рисовании он и формируется - вот и пусть хранится только во второй мапе.

Говоря о др решениях я имел ввиду нечто принципиально другое чем "шаред + наблюдающий weak". А иначе нет смысла ломать логику классов из-за технической детали. Можно хотя бы просто при каждом получении кеша (и отключении клиента) тупо проходиться по второй мапе удаляя сдохших weak. В данном случае это приемлемо т.к. число эл-тов в ней невелико. Собственно никто не мешает записать что-то в кеш и в деструкторе кеша это использовать - но вот не пока соображу что и как.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #23 : Октябрь 31, 2015, 07:54 »

Конечно можно, но весь этот код начинает литься в клиента, а там он совершенно неуместен. Клиент не должен ничего знать от том кто и как его кеширует, это не его дело. Даже хранение Key2 в клиенте плохо, т.к. Key2 это большой набор данных с массой подробностей рисования. Именно на рисовании он и формируется - вот и пусть хранится только во второй мапе.
Я не знаю подробностей вашей задачи. Считаете что не должен, пусть будет так.

Собственно никто не мешает записать что-то в кеш и в деструкторе кеша это использовать - но вот не пока соображу что и как.
Если вы напишите примерное api на эту систему кеширования (как я просил в прошлом сообщении), тогда можно будет что-то советовать.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Октябрь 31, 2015, 18:10 »

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

- вот есть вполне нормальная схема: shared + weak, оба хранятся в мапах. Можем добавлять любые данные к ключам и значениям обеих мапов. Как лучше всего обеспечить удаление "отжившего" weak значения? Конечно "можно как-то обойтись без одной из мапов" - но за это придется заплатить чем-то другим. Зачем, разве удаление weak - нерешаемая задача?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #25 : Октябрь 31, 2015, 18:17 »

Я спросил про API для того, что если у вас есть функция или метода типа freeCkient( int keyClient ), которая удаляет информацию о клиенте из первой map, то чистить указатель во второй map можно из него. Если его нет, то можно сделать специальный контейнер для кеша и чистить вторую map из его деструктора.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #26 : Октябрь 31, 2015, 18:29 »

Специальный контейнер это не коллекция для объектов кеша, а класс обертка над указателем на данные кеша.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Ноябрь 01, 2015, 08:24 »

Я спросил про API для того, что если у вас есть функция или метода типа freeCkient( int keyClient ), которая удаляет информацию о клиенте из первой map, то чистить указатель во второй map можно из него.
Конечно такой метод есть, его просто не может не быть. Но это не единственное место удаления кеша. К тому же используется QSharedPointer который use_count не имеет, а С++11 в проекте, увы - пока не используется, что зависит не от меня. И надо где-то хранить Key2 (ключ-монстр). Словом - тут немалые трудности.

Если его нет, то можно сделать специальный контейнер для кеша и чистить вторую map из его деструктора.
Вот это интересно, в рамках 2 мапов (класса где они сидят) у меня никаких ограничений нет, он кешированию и посвящен.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #28 : Ноябрь 01, 2015, 09:33 »

Конечно такой метод есть, его просто не может не быть. Но это не единственное место удаления кеша.
Нам нужно не само удаление кеша, а момент удаления клиента из map1. В этот момент может произойти удаление неиспользуемого кеша и необходимость почистить map2.

К тому же используется QSharedPointer который use_count не имеет
Печально. Будем ждать появления такого функционала где нибудь в Qt6. Они QEnableSharedFromThis умудрились сделать только в Qt5.4, хотя QSharedPointer у них появился еще в Qt4.5. Улыбающийся

И надо где-то хранить Key2 (ключ-монстр). Словом - тут немалые трудности.
Без определения уникальности в этом нет смысла. Проще после каждого удаления клиента из map1 пробегаться по map2 и удалять опустевшие указатели.

Вот это интересно, в рамках 2 мапов (класса где они сидят) у меня никаких ограничений нет, он кешированию и посвящен.
Имелся ввиду контейнер для указателя на данные кеша. При удалении этого объекта (а это случается, когда из map1 удаляется последний клиент его использующий) он в деструкторе подчищал map2.
Но если у вас специальный метод, то проще все это сделать в нем.
« Последнее редактирование: Ноябрь 01, 2015, 10:57 от Old » Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #29 : Ноябрь 04, 2015, 00:25 »

Добрый день

Запутался с, казалось бы, простой задачей. Есть 2 мапы
Код
C++ (Qt)
std::map<Key1, Value *> map1;
std::map<Key2, Value *> map2;
 
Обе мапы хранят полный (и одинаковый) набор Value. В первой мапе эл-ты с разными ключами могут иметь одно и то же значение. Во второй все значения уникальны (а не только ключи). Др словами первая - чтобы собственно пользоваться, вторая - чтобы "валидировать".

Клиент, располагая 2-мя ключами, ищет 2 значения Value в map1 и map2. Если они ненулевые и совпали - все хорошо, возвращается найденный указатель. Иначе если эл-т не найден в map2 то новый Value должен быть создан и помещен в обе мапы. Если найден то замещает значение в map1[key1]. В любом случае если оказалось что старый (замещаемый) эл-т в map1 больше в ней никем не используется - значение должно быть удалено и вычеркнуто из map2. Др словами обе мапы все время должны хранить полный и одинаковый набор значений.

Как же здесь могут помочь вумные указатели?  Улыбающийся

Спасибо

std::set<значений>
и std::map<ключ, итератор значений>
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


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