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

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

Страниц: 1 ... 9 10 [11] 12 13 ... 17   Вниз
  Печать  
Автор Тема: Igors, это ты? :)  (Прочитано 131972 раз)
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #150 : Декабрь 04, 2018, 11:43 »

Цитировать
если бы не одно "но" - если m_Object удален, то придется бегать и обнулять его во всех клиентах.

Ну так сделайте его отслеживаемым (trackable).. Помнится, это уже обсуждалось:
Код
C++ (Qt)
#include <iostream>
#include <memory>
 
class trigger
{
public:
   trigger() : m_flag(true) {}
   bool get() const { return m_flag; }
 
   friend class trackable;
 
private:
   void set(bool flag) { m_flag = flag; }
   bool m_flag;
};
 
typedef std::shared_ptr<trigger> spy_type;
 
class trackable
{
public:
   trackable(const trackable &)
       : spy(std::make_shared<trigger>())
   {}
 
   trackable()
       : spy(std::make_shared<trigger>())
   {}
 
   trackable &operator=(const trackable &) { return *this; }
 
   ~trackable() { spy->set(false); }
   spy_type spy;
};
 
 
struct SomeObject : public trackable
{
   //...
};
 
struct SomeClient
{
   SomeObject * m_Object;
 
   bool objectIsValid() const { return (spy) ? spy->get() : false; }
 
   void setObject(SomeObject * obj)
   {
       m_Object = obj;
       spy = obj->spy;
   }
 
private:
   spy_type spy;
};
 
 
int main()
{
   SomeClient Client;
 
   std::cout << std::boolalpha << Client.objectIsValid() << std::endl;
 
   SomeObject * Object = new SomeObject();
 
   Client.setObject(Object);
 
   std::cout << Client.objectIsValid() << std::endl;
 
   delete Object;
 
   std::cout << Client.objectIsValid() << std::endl;
 
   return 0;
}
 
 
https://ideone.com/q3IbxF
Undo тоже не сложно реализовать..
« Последнее редактирование: Декабрь 04, 2018, 12:02 от m_ax » Записан

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

Arch Linux Plasma 5
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #151 : Декабрь 04, 2018, 13:46 »

Быстрая (практически бесплатная) вставка у него по определению. Вот с ним ота песня с итераторами вполне уместна.
...
Увеличу размер QList и расчищу в нем место для новых эл-тов сместив "хвост" (заодно будет возможность подучить конструктор перемещения). Потом скопирую. Возможно оформлю темплейтом.

Без доступа к методам reserve(), end() ничего не выйдет.

Я говорил в общем о подходе. Определяется необходимый и достаточный набор методов для контейнеров (в STL описываются в Named requirements), остальное выносится в алгоритмы.

Если вот это всё вместе сложить, что получится? Улыбающийся

В С++20 будут добавлены Concepts, с их помощью можно узнать, есть ли в классе определенные типы/методы/поля. В С++17 уже есть if constexpr. С этими возможностями можно сделать алгоритм:
1. В классе есть свой метод insert(pos, first, last) - используем его напрямую.
2. Есть reserve(), end() (условно) - с их помощью реализуется обобщенный алгоритм вставки диапазона.
3. Есть одиночный insert(pos, value) - вставляем в цикле по одному. Тупо и для некоторых контейнеров дико не эффективно - а шо делать, хоть как-то надо вставить.
4. Ничего подходящего нет - ошибка компиляции.

Может "встроенные" методы insert(pos, first, last) в контейнерах и есть "необходимый и достаточный набор", и с помощью "reserve(), end()" не всегда или не для всех контейнеров можно написать обобщенный алгоритм, тут я ничего точно утверждать не могу, так глубоко в тему не погружался. Но в С++20 добавятся ещё и Ranges, и чтобы была возможность вставки Range в контейнер, что будут делать: добавлять в каждый контейнер перегрузку insert с параметром Range, или сделают внешнюю функцию (ака алгоритм), которая этот Range передаст в виде итераторов в метод insert контейнера? И будут ли у этой внешней функции перегрузки для итераторов? Делаем ставки Улыбающийся.

Код
C++ (Qt)
QWeakPointer<SomeObject> m_Object;
Код
C++ (Qt)
QPointer<SomeObject> m_Object;

Посмотрите в исходниках, что из себя представляет этот QPointer Подмигивающий.

Типовая ситуевина - клиент не владеет m_Object, не отвечает за его создание/удаление, т.е. клиент его просто использует - и все.
...
Но это вынуждает владельца объявлять его шаред, а это головняк, надо все время смотреть не зашарился ли он где еще. И почему-то автоматом предполагается "продление жизни". Чего это? Я ничего продлевать не просил.

Если "клиент не владеет m_Object, не отвечает за его создание/удаление, т.е. клиент его просто использует" и "надо все время смотреть не зашарился ли он где еще", можно ли сказать, что кто-то владеет SomeObject уникально, а SomeClient имеет "невладеющую ссылку" на него? std тогда предлагает для владения unique_ptr, и голый указатель или observer_ptr в качестве "невладеющей ссылки". Но если unique_ptr удалится (вместе с объектом), то ни голый указатель, ни observer_ptr об этом не узнают. Это и была одной из основных причин(плюс ещё многопоточность), по которой я начал мутить свои указатели. Но некоторые (не Вы) говорят, что shared_ptr хватит для всех, чтобы он еще где-то не шарился - "так смотрите внимательнее, что пишите", а что из weak_ptr можно получить shared_ptr - "так сам дурак, раз так делаешь" Улыбающийся. Но чтобы shared_ptr таки нельзя было так просто шарить дальше, на пальцах показали такое решение , можете воспользоваться Улыбающийся.

Как же так? Случай простейший ("элементарный" и.т.п.) - всего-навсего член-указатель, а никаких средств не видать, приходится городить велики (а шо делать?)

Вот и я вопрошал: "Доколе?" Улыбающийся. Но ждать не стал, и сделал себе велик сам. Нужен ли такой в std? Не уверен, может даже скорее "нет", потому как в upl::unique присутствуют накладные расходы, в отличие от std::unique_ptr. В качестве сторонней библиотеки - каждый сам решает, для меня-то она не сторонняя Улыбающийся. К тому же она интегрирована с std, насколько это возможно.
Записан

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

Сообщений: 11445


Просмотр профиля
« Ответ #152 : Декабрь 05, 2018, 16:05 »

Ну так сделайте его отслеживаемым (trackable).. Помнится, это уже обсуждалось:
...
Undo тоже не сложно реализовать..
Да, ясно: создадим флажок и пусть его шарят объект и клиент(ы). Объект при удалении сбрасывает флажок, и, увидев это false, клиент узнает что объект уже удален. Критика:

- (используемым) объектом может быть очень многое, поэтому навязывание интерфейса trackabe всем и каждому не радует

- клиент: мне кажется более естественным хранить указатель и шаред флажок в структуре, снабдив ее бесхитростным методом get(). Чтобы не дорисовывать методы если появятся еще такие "используемые" указатели

Но это все цветочки. Главное - от беготни с поиском "кто ссылается на объект" эта конструкция никак не избавляет. Можно оборачивать шаред так и сяк - но он хранит только "факт ссылки". Собсно любая "вумность" указателей на этом и заканчивается. Пример: та же запись данных для undo. Известно что SomeObject грохнут, значит надо найти клиентов - а никакой инфы о них в SomeObject нет. Приходится решать это "как-нибудь" (напр пробежкой по глобальному списку объектов, или сигналами или еще как). Но тогда зачем городить еще какие-то конструкции - ведь найдя клиента можно просто обнулить в нем указатель - и все.

Не спорю, просто "указатель с валидностью" тоже неплохо, иногда достаточно и его, но часто/обычно нет.



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

Сообщений: 3260


Просмотр профиля
« Ответ #153 : Декабрь 05, 2018, 16:14 »

Igors
хз, свазок shared/weak и unique/observer достаточно ИМХО для любых нужд.
К примеру весь парент-чайлд Qt делается при помощи второй.
Код:
auto parent = std::make_unique<QMainWindow>();
std::observer_ptr<QWidget> w1 = QObject::makeChild<QWidget>(parent);
auto w2 = std::make_unique<QWidget>();
w1->addChild(std::move(w2));

Вот, к примеру, ваше любимое дерево. Думаю завернуть в шаблон через идиому base/derived и таскать между проектами
« Последнее редактирование: Декабрь 05, 2018, 16:22 от Авварон » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #154 : Декабрь 05, 2018, 16:50 »

Цитировать
- (используемым) объектом может быть очень многое, поэтому навязывание интерфейса trackabe всем и каждому не радует
Не нравится наследование, сделайте trackable членом класса, например..

Цитировать
Но это все цветочки. Главное - от беготни с поиском "кто ссылается на объект" эта конструкция никак не избавляет. Можно оборачивать шаред так и сяк - но он хранит только "факт ссылки". Собсно любая "вумность" указателей на этом и заканчивается. Пример: та же запись данных для undo. Известно что SomeObject грохнут, значит надо найти клиентов - а никакой инфы о них в SomeObject нет. Приходится решать это "как-нибудь" (напр пробежкой по глобальному списку объектов, или сигналами или еще как). Но тогда зачем городить еще какие-то конструкции - ведь найдя клиента можно просто обнулить в нем указатель - и все.
Это решается с помощью некоторого manager'а, который знает какие клиенты подписаны/следят за SomeObject. И в деструкторе m_Object просто пинаете этого менеджера, чтоб он автоматически передавал сигналы (со всеми необходимыми данными для undo) всем подписанным клиентам. Тогда не придётся "руками" бегать по всему списку..
Записан

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #155 : Декабрь 05, 2018, 17:34 »

Это решается с помощью некоторого manager'а, который знает какие клиенты подписаны/следят за SomeObject. И в деструкторе m_Object просто пинаете этого менеджера, чтоб он автоматически передавал сигналы (со всеми необходимыми данными для undo) всем подписанным клиентам. Тогда не придётся "руками" бегать по всему списку..
Да, такие наметки напрашиваются, но.. это выглядит совсем другой задачей, никак не связанной ни с "вумными указателями" ни с новыми "сущностями" в стандарте. По сути мы признаем что эти фичес так, "мелочь по карманам тырить" (валидный указатель но не серьезный менеджер). Ну не знаю, я бы с такими выводами не спешил, все-таки задача выглядит весьма общей.

хз, свазок shared/weak и unique/observer достаточно ИМХО для любых нужд.
К примеру весь парент-чайлд Qt делается при помощи второй.
Код:
auto parent = std::make_unique<QMainWindow>();
std::observer_ptr<QWidget> w1 = QObject::makeChild<QWidget>(parent);
auto w2 = std::make_unique<QWidget>();
w1->addChild(std::move(w2));
"То що це йому дало?". Расскажите чего Вы таким образом добились, observer_ptr только мельком глядел, по смыслу вроде"само то" но ни одного примера нет и experimental
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #156 : Декабрь 05, 2018, 18:14 »

Цитировать
Да, такие наметки напрашиваются, но.. это выглядит совсем другой задачей, никак не связанной ни с "вумными указателями" ни с новыми "сущностями" в стандарте. По сути мы признаем что эти фичес так, "мелочь по карманам тырить" (валидный указатель но не серьезный менеджер). Ну не знаю, я бы с такими выводами не спешил, все-таки задача выглядит весьма общей.
В std и не должно быть решений на все случаи жизни. Она даёт концепции и инструментарий/кирпичики из которых уже можно сложить и manager и клиентов и т.д.. 
Записан

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

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

Сообщений: 3260


Просмотр профиля
« Ответ #157 : Декабрь 05, 2018, 20:05 »

"То що це йому дало?". Расскажите чего Вы таким образом добились

Того, что по сигатуре функции видно, кто кем владеет.
Код:
QAbstractItemModel *QAbstractItemView::model() const

Возвращаемый указатель надо удалять? Или его вью удалит? А если я всё-таки удалю, что произойдет?
А тут?
Код:
QGraphicsRectItem *QGraphicsScene::addRect()
А тут?
Код:
void QDataStream::setDevice(QIODevice *d)
Чуете проблему, к каждой функции приходится писать пространные объяснения кто кем владеет или догадываться по словам add/set. Думаю, если поискать, то можно найти неочевидных контрпримеров в АПИ Qt.

observer_ptr только мельком глядел, по смыслу вроде"само то" но ни одного примера нет и experimental

Ну обычный "вумный" указатель, который не владеет и за временем жизни не следит (как делает weak/QPointer). Используется чтобы показать, что объект удалять не надо, им владеет кто-то ещё как-то ещё и что он может быть удален. Апи 1в1 как у unique_ptr или shared_ptr (operator*, ->, bool, метод get()).

Например:
Код:
std::observer_ptr<QIODevice> QDataStream::device(d) const;
void QDataStream::setDevice(std::observer_ptr<QIODevice> d);

Видно, что датастрим хранит указатель на объект но им не владеет.

Я юзаю его так
Впрочем, мб уже и под вендой появилось
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #158 : Декабрь 06, 2018, 10:24 »

Возвращаемый указатель надо удалять? Или ...
Когда-то читал отличный учебник английского языка. Там примерно так
Цитировать
Если увидели глагол с предлогом - никогда не полагайтесь на здравый смысл, всегда открывайте словарь
.
Видно, что датастрим хранит указатель на объект но им не владеет.
Здесь немного "не вкурил", ну ладно, не все сразу. Спасибо

В std и не должно быть решений на все случаи жизни. Она даёт концепции и инструментарий/кирпичики из которых уже можно сложить и manager и клиентов и т.д..  
Ну так давайте складывать. Боюсь что реальная реализация не будет использовать никаких std концепций/кирпичиков Улыбающийся Напомню чего мы хотим - имея объект уметь находить всех ссылающихся на него. Ну и, само собой, уметь добавлять/удалять эти ссылки. При этом никакого владения нет, более того, даже цикличные ссылки могут быть разрешены.

Не нравится наследование, сделайте trackable членом класса, например..
Это чуть приятнее, но все равно накладно - придется добавлять этот член везде. И тогда не будет общей возможности взять target (на что ссылаемся). А не сделать ли хранение ссылок вообще "внешним"? Тогда использование может выглядеть напр так
Код
C++ (Qt)
CSomeObject * refTarget;    // на него ссылаемся
CAnotherObject * refНandle; // а этот ссылается на кого-то
 
... // устанавливаем связь между объектами
СReferenceManager::InstallLink(refTarget, refHandle, LINK_TYPE_DEFAULT);
..
// имея target перебираем ссылающихся
int numLinks = СReferenceManager::GetHandleCount(refTarget); // вернет 1 (один объект ссылается)
int linkType, index = 0;
void * handle = СReferenceManager::GetIndexedHandle(refTarget, index, &linkType);
void * handle2 = СReferenceManager::GetTypedHandle(refTarget, LINK_TYPE_DEFAULT);
...
// имея ссылающегося извлекаем target
void * target = СReferenceManager::GetTarget(refНаndle, LINK_TYPE_DEFAULT);
 
Понимаю, это совсем не модно Улыбающийся, да и с void'ами надо подумать. Ограничения - объект(ы) должен быть неперемещаемым. И в деструкторе объект должен позвать СReferenceManager, не вижу никакой возможности это проконтролировать (да, минус). Зато в остальном - нет никаких обязательств, интерфейсов и.т.п.

Критикуем, пинаем...
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #159 : Декабрь 06, 2018, 12:11 »

Понимаю, это совсем не модно Улыбающийся, да и с void'ами надо подумать.

Да, осталась самая малость - понять, что с этими объектами, ссылающимися на заданный, вообще можно делать Улыбающийся. Вот получили с помощью СReferenceManager::GetIndexedHandle(refTarget, index, &linkType) какой-то объект, что с ним можно делать?
Записан

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

Сообщений: 2095



Просмотр профиля
« Ответ #160 : Декабрь 06, 2018, 17:01 »

Цитировать
Понимаю, это совсем не модно  Улыбающийся, да и с void'ами надо подумать.
Я вообще перестал понимать, что здесь происходит)
Если максимально упростить задачу, то в этой истории останется 3 персонажа (в моём понимании): Client (их может быть много), Object,  который используют клиенты и Manager, который контролирует время жизни Object и оповещает всех клиентов, когда тот удаляется.

Вот как пример (на коленке) иллюстрирующий это:
Код
C++ (Qt)
#include <iostream>
#include <list>
 
class Object
{
   //...
};
 
class Client
{
public:
   Object * m_Object;
 
   void makeUndo()
   {
       // ...
       m_Object = nullptr;
   }
};
 
class Manager
{
public:
   Manager(Object * obj = nullptr)
       : m_object(obj)
   {}
 
   void addClient(Client * client)
   {
       m_subscribers.push_back(client);
   }
 
   void killObject()
   {
       for (auto c : m_subscribers)
           c->makeUndo();
 
       delete m_object;
       m_object = nullptr;
   }
 
private:
   Object * m_object;
   std::list<Client*> m_subscribers;
};
 
 
int main()
{
   Object * obj = new Object;
 
   Client client1;
   Client client2;
 
   client1.m_Object = obj;
   client2.m_Object = obj;
 
   Manager manager(obj);
 
   manager.addClient(&client1);
   manager.addClient(&client2);
 
   manager.killObject();
 
   return 0;
}
 
 
Записан

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #161 : Декабрь 06, 2018, 17:46 »

Да, осталась самая малость - понять, что с этими объектами, ссылающимися на заданный, вообще можно делать Улыбающийся. Вот получили с помощью СReferenceManager::GetIndexedHandle(refTarget, index, &linkType) какой-то объект, что с ним можно делать?
Как уже говорилось, объект "используется" клиентом, т.е. клиент просто-напросто дергает методы объекта, ну или читает/пишет его public члены. Напр в случае undo нужно записать в файл пару уникальных ID (объекта и клиента), чтобы, если дело дойдет до undo, восстановить связку. А если таких связок несколько (почему нет), то дополнительно еще и идентификатор связки (linkType). Итого: при выполнении undo (перед удалением Object) значение возвращаемое GetIndexedHandle используется для получения уникального ID этого клиента.

Я вообще перестал понимать, что здесь происходит)
Если максимально упростить задачу, то в этой истории останется 3 персонажа (в моём понимании): Client (их может быть много), Object,  который используют клиенты и Manager, который контролирует время жизни Object и оповещает всех клиентов, когда тот удаляется.
Изначально персонажей только 2 - клиент(ы) и (используемый) объект. Клиенты должен знать объекты, которые они используют, а объекты - всех использующих клиентов. Как это реализуется (с manager'ом или без) - дело разработчика. Также "оповещение" (типа "ссылка изменилась") - вариант возможный но совсем не единственный (см пример undo выше)
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #162 : Декабрь 07, 2018, 11:04 »

Клиенты должен знать объекты, которые они используют, а объекты - всех использующих клиентов.

Эти клиенты/ссылающиеся одного типа (или имеют общий базовый тип)? Или могут быть несвязанными между собой типами и ссылаться на один объект?
Записан

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

Сообщений: 2095



Просмотр профиля
« Ответ #163 : Декабрь 07, 2018, 14:44 »

Цитировать
Эти клиенты/ссылающиеся одного типа (или имеют общий базовый тип)? Или могут быть несвязанными между собой типами и ссылаться на один объект?
Меня тут другой вопрос вопрос беспокоит: С какого кхм-кхм.. объекту знать о всех клиентах? Улыбающийся
Записан

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

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

Сообщений: 4350



Просмотр профиля
« Ответ #164 : Декабрь 07, 2018, 17:51 »

Клиенты должен знать объекты, которые они используют, а объекты - всех использующих клиентов.
И все это поместить в MainWindow и композиция будет завершенной. Улыбающийся
Записан
Страниц: 1 ... 9 10 [11] 12 13 ... 17   Вверх
  Печать  
 
Перейти в:  


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