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

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

Страниц: [1] 2 3 4   Вниз
  Печать  
Автор Тема: Помогите с умными указателями  (Прочитано 26170 раз)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« : Май 07, 2015, 14:57 »

Привет. Так уж довелось что за время работы с с++ умными указателями практически не пользовался.
А тут решил перевести свой код на их использование. Возникла проблема понимания QSharedPointer и QWeakPointer.

Опишу проблему и надеюсь услышать советы по оптимизации.

Есть несколько базовых объектов-синглтонов, которые предоставляют доступ к некоторым данным. Каждый синглтон отвечает за свои данные. Синглтоны реализованы в разных либах.
Есть так же несколько синглтонов, которые используют базовые синглтоны (назовем их композитные). Так же реализованы в разных либах.

Вот код базового синглтона
base.h
Код:
class   CBaseManager;
typedef QSharedPointer<CBaseManager>   BaseManager;

class RAILCORESHARED_EXPORT CBaseManager : public  CManagerInterface, //наслденик от QObject
                                                        public  CDocumentItemInterface //интерфейс сериализации
{
Q_OBJECT

    static      BaseManager finstance;

protected:
    friend  class   QSharedPointer<СBaseManager>;
    explicit СBaseManager(QObject *parent = 0);
public:

    ~СBaseManager();
    static  BaseManager   instance();

Код:
СBaseManager СBaseManager::instance()
{
    if(finstance.isNull())
       finstance = BaseManager::create();
    return  finstance;
}

Т.е. базовый синглтон создается при первом вызове, а далее только инкрементируется его счетчик ссылок, и удаляется после того как на него никто не ссылается.

Вот пример композитного синглтона
Код:
class CTrainManager;
typedef QSharedPointer<CTrainManager>   TrainManager;

class TRAINSSHARED_EXPORT CTrainManager : public CManagerInterface, public CDocumentItemInterface, private CEventDispatcherListener, private CFeatureManagerInterface
{
    Q_OBJECT

    static  TrainManager                    finstance;

BaseManager1                fmanager1; //QSharedPointer<CBaseManager1>
BaseManager2                fmanager2;
..
BaseManagerN                fmanagerN;
}

Такой вопрос, нужно хранить shared_ptr или weak_ptr в композитных синглтонах?
Собственно это делается изза того, что я не знаю как инициализировать синглтон в библиотеке до запуска основного приложения.
Не хочется лепить какие то костыли. К тому же эти синглтоны у меня используются в очень многих местах программы и некоторые связаны между собой.

Или например в каком то объекте (диалоговом окне например) нужно получить досутп к данным определенного синглтона. я копирую shared_ptr. Правильно ли я делаю в данном случае?
Прочитал много статей и инфы, но в целом картина с shared_ptr проясняется, а вот с weak_ptr не очень.
Записан
Tuxford
Гость
« Ответ #1 : Июль 30, 2015, 11:02 »

weak_ptr не будет удален пока не будут грохнуты все shared_ptr, которые на него ссылаются. 
Что-то не вижу причин использовать weak_ptr. Не вижу в этом коде циклических ссыллок.

Вообще делать такого дикобраза на синглтонах - то же самое что ходит по минному полю. В свое время на такие яйца нарывался. Больше не хочу. Синглтон - зло.
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #2 : Август 01, 2015, 08:11 »

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

представленный код - один большой костыль.

рецепт сингелтона:

Код:
struct sample
{
    static sample& Get()    { static sample s; return s; }
};

не нужны никакие смартпоинтеры.
сингелтон не убиваем.

если это не так - значит это будет более глючная и сволочная конструкция,
которая провоцирует ошибки и только усложняет жизнь.

Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #3 : Август 01, 2015, 08:12 »

Синглтон - зло.

много раз слышал.
ни разу не получил ни одного вразумительного ответа на вопрос:
а почему собственно?

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

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Август 01, 2015, 09:19 »

Синглтон - зло.

много раз слышал.
ни разу не получил ни одного вразумительного ответа на вопрос:
а почему собственно?
Присоединяюсь к вопросу. Не все в синглтоне хорошо, но часто я не нахожу лучшего решения. Ну вот хотя бы
Код
C++ (Qt)
MyMenuManager::Instance()->AddSomething();
Где MyMenuManager - синглтон. (Главное) Меню в приложении одно, а нужно всем, из совершенно разных мест никак не связанных между собой. Почему я должен избегать синглтона, и что вместо него?

Недостатки заметны когда я пытаюсь задействовать MyMenuManager уже в др приложении. Ну да приходится подлатать с #ifdef  Улыбающийся
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #5 : Август 01, 2015, 15:42 »

Недостатки заметны когда я пытаюсь задействовать MyMenuManager уже в др приложении. Ну да приходится подлатать с #ifdef  Улыбающийся

у меня единственная причина отказа от сингелтона -
издержки связанные с многопоточностью.

иногда лучше иметь локальные копии переменных,
пусть даже их придется передавать по многим аргументам,
но не иметь проблем с синхронизацией.
Записан
Tuxford
Гость
« Ответ #6 : Август 02, 2015, 22:32 »

Синглтон - зло.

много раз слышал.
ни разу не получил ни одного вразумительного ответа на вопрос:
а почему собственно?


1. Глобальная переменная. Неявная инициализация/деинициализация. Просто говоря может инициализироваться или там или там или там. Особенно весело есть есть зависимости между синглтонами. В простеньких проектах все хорошо. Но вот когда все разрастется, вот там танцы с бубном обеспечены.
2. Две разные респонсибилити: инициализация и контроль. Это уже больше вопрос проектирования. Насколько архитектура вашего приложения хороша.
3. Если вы работали с ТДД, попробуйте создать мок-объект синглтона. Ну-ну. Поделитесь опытом как правильно сделать.

Чем заменить? Фабрикой с явной инициализацией.
« Последнее редактирование: Август 02, 2015, 22:34 от Tuxford » Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #7 : Август 03, 2015, 10:33 »

действительно, я пришёл к фабрикам с явной инициализацией. Искал в шаблонах проектированя, но пришёл к фабрикам. По сути есть один синглтон, задача которого создавать глобальные объекты из фабрик, хранить у себя и возвращать их по запросу. При этом у каждого такого глобального объекта есть своя приватная статическая переменная, которая указывает на единстенный экземпляр.
После того как все глобальные объекты созданы, я их инициализирую, т.е. на момент инициализации все необходимые объекты уже есть в наличии.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Август 03, 2015, 15:21 »

Ну-ну..
Мне доводы не кажутся убедительными, но они звучат столь категорично/безапеляционно, так что лучше не спорить  Улыбающийся, ограничусь одним замечанием ниже

Чем заменить? Фабрикой с явной инициализацией.
действительно, я пришёл к фабрикам с явной инициализацией.
Ой как хорошо чувствовать что, мол, "на правильном пути" Улыбающийся Только что изменилось если вместо одного "ярлычка" навесили другой? Все равно экземпляр один, все равно все зависимости отслеживать.

Возвращаясь к вопросу "для чего weak_ptr". Хорошая штука, пусть и не так уж часто нужна. Он не "удерживает" указатель (в отличие от shared_ptr), т.е. если кто-то другой его освободил, объект может быть удален. Но "weak" позволяет узнать "жив ли" указатель, это ценная возможность. Как только задействован shared_ptr, "обычный" указатель уже не катит, а копируя shared мы сами "держим" объект, это не всегда то что нужно.
Записан
Tuxford
Гость
« Ответ #9 : Август 03, 2015, 15:52 »

Вы в курсе, что такое ТДД? Работали с множеством синглтонов? Скорее всего нет. Поробатаете на большом проекте с десятком синглтонами, тогда 100% мнение измените.

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

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Август 03, 2015, 16:50 »

Вы в курсе, что такое ТДД? Работали с множеством синглтонов? Скорее всего нет. Поробатаете на большом проекте с десятком синглтонами, тогда 100% мнение измените.

Объект один - то что и нужно. Только без глобальных переменных и прочих прелестей, которые делает синглтон. При этом все очевидно и связаность кода меньша.
Ну у меня десятка 2 точно (может и больше) наберется  Улыбающийся И, пожалуйста, не надо "играть в учителя", наивно мня что у Вас-то уж точно "опыта побольше" Улыбающийся Отвечайте по существу, а не так, "на понтах" - здесь это не катит. Напр покажите (на простом примере, псевдокод) Ваш метод/подход. Словом, давайтe "обсуждать", а не "диктовать". Спасибо за понимание.
Записан
Tuxford
Гость
« Ответ #11 : Август 04, 2015, 10:30 »

Пожалуйста. Самый примитивный пример.
Код:
class UpdateDownloadManager
{
  static UpdateDownloadManager* pInstance;
public:
  static instance();
  void apply(const std::string& url);
private:
  UpdateDownloadManager();
  Items compareWithLocal();
  void saveNewState(const Items& items);
}

class Storage
{
   static Storage* pInstance;
  public:
    static instance();
    Storage(const std::string& path);
    void save(const Items& items);
    Items load();
}


И так формально оба класса должны быть синглтонами.
Следуя вашей логики, реализация должна быть такая.
Код:
void UpdateDownloadManager::apply(const std::string& url)
{
  Items dwlItems = Download(url);
  StoragePtr pStorage = Storage::instance();
  Items localItems = pStorage->getLocal();
  Items diff = compareWithLocal(localItems , dwlItems);
  doUpdate(diff);
  saveNewState(diff);
}

void UpdateDownloadManager::saveNewState(const Items& items)
{
  StoragePtr pStorage = Storage::instance();
  pStorage->save(items);
}
Все хорошо. А теперь напишите юниттесты дла этого дела, чтобы протестить весь код. Я не вижу такой возможности.

Теперь немного переиначим.
Код:
class UpdateDownloadManager
{
public:
  UpdateDownloadManager(const std::string& url, IStoragePtr pStorage);
  void apply();
private:
  UpdateDownloadManager();
  Items compareWithLocal();
  void saveNewState(const Items& items);
private:
  IStoragePtr pStorage;
}

class Storage : public IStorage
{
  public:
    Storage(const std::string& path);
    virtual void save(const Items& items);
    virtual Items load();
}
И реализация:
Код:
void UpdateDownloadManager::apply(const std::string& url)
{
  Items dwlItems = Download(url);
  Items localItems = pStorage->getLocal();
  Items diff = compareWithLocal(localItems , dwlItems);
  doUpdate(diff);
  saveNewState(diff);
}

void UpdateDownloadManager::saveNewState(const Items& items)
{
  pStorage->save(items);
}

Ну и пишем фабрику. Думаю все догадаются как это делать.
В результате. Манагеру подсовываем легко фейковый сторедж и тестим себе все что угодно. Никаких глобальных состояний. Инициализацией занимается фабрика. Все чудненько.

« Последнее редактирование: Август 04, 2015, 10:32 от Tuxford » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Август 05, 2015, 09:30 »

Все хорошо. А теперь напишите юниттесты дла этого дела, чтобы протестить весь код. Я не вижу такой возможности.
Насколько я понял, это главный, он же единственный и убийственный аргумент. Но скажите, почему я должен писать какие-то тесты? Наверное у Вас на работе такой порядок, ну раз надо так надо. Но у меня такого нет, почему Вы решили что эти правила должны неуклонно соблюдаться всеми?  Улыбающийся

Не так уж давно был подобный случай: "так нельзя потому что... нарушается БИНАРНАЯ СОВМЕСТИМОСТЬ!". Тоже придумали "священную корову". Не спорю, и TDD и "совместимость" смысл имеют, может в Ваших проектах они даже необходимы, не мне судить. Но требовать от всех делать то же самое - это, мягко говоря, чересчур
Записан
Tuxford
Гость
« Ответ #13 : Август 05, 2015, 10:24 »

Чтобы продемострировать всякие лажи которые бывают из-за инициализаций, придется много выложить кода. В даном случае может сыграть даже порядок линковки и пр. прелести. Вариантов очень много.
« Последнее редактирование: Август 05, 2015, 10:43 от Tuxford » Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #14 : Август 06, 2015, 01:42 »

1. Глобальная переменная. Неявная инициализация/деинициализация. Просто говоря может инициализироваться или там или там или там. Особенно весело есть есть зависимости между синглтонами. В простеньких проектах все хорошо. Но вот когда все разрастется, вот там танцы с бубном обеспечены.
2. Две разные респонсибилити: инициализация и контроль. Это уже больше вопрос проектирования. Насколько архитектура вашего приложения хороша.
3. Если вы работали с ТДД, попробуйте создать мок-объект синглтона. Ну-ну. Поделитесь опытом как правильно сделать.

Чем заменить? Фабрикой с явной инициализацией.

1.
ну так в этом и есть цемес: глобальная точка доступа.

по поводу "неявной инициализации" не понятно.
что значит неявно?

вызывающая сторона зовет сингелтон,
и он полностью в рабочем состоянии,
предоставляет услуги.

вызывающей стороне не нужно думать,
как именно он инициализируется.
и это здорова - инкапсуляция позволяет сразу же получать профит,
не заморачиваясь детали внутреннего устройства.

в чем проблема то?

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

2.
не понятно, что значит "респонсибилити" ?
тезис вообще не понятен.

3.
я работаю по методике ТДД, и ни разу не возникла потребность его мокать.
однако, если бы потребовалось - не вижу в этом никаких выполнить статическую подмену:

Код:
singelton<system>

на

Код:
singelton<face_system>

я предлагаю вам не делать голословных утверждений в духе "а вы попробуйте, ну-ну".
вместо этого: проиллюстрируйте проблему.



Записан
Страниц: [1] 2 3 4   Вверх
  Печать  
 
Перейти в:  


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