Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / С++ где взять shared_ptr когда он так нужен? [РЕШЕНО]

С++ где взять shared_ptr когда он так нужен? [РЕШЕНО]

Страницы: 1 2 3 4 5 6 Следующая »
grishmanПользовательwww5 июля 201821:41#0
Привет всем. У меня проблемы с архитектурой на умных указателях. Есть два класса: Widget и WidgetContainer.
Каждый виджет может иметь только одного родителя, которым может быть только ContainerWidget. Внутри каждого контейнера может быть любое количество виджетов. Получается что-то такое:
class Widget
{
     private: weak_ptr<ContainerWidget> parent;
     ...
 
     private: void SetParent(shared_ptr<ContainerWidget> _widget);
};


class ContainerWidget: public Widget
{
      private: map<string, shared_ptr<Widget>> widgets;
      ....

      public: bool AddWidget(shared_ptr<Widget> _widget)
      {
          ...
          // _widget нам подходит, добавляем его в контейнер widgets;
          // вот здесь нужно что-то вроде _widget->SetParent(shared_ptr<ContainerWidget>(this)); но так делать нельзя
          return true;
      }
};

Каким образом мы можем корректно получить умный указатель на this изнутри класса? Пока нашел только такую дичь, от которой стало не по себе. Может существуют другие решения?

DelfigamerПостоялецwww5 июля 201821:50#1
grishman
А как ты себе представляешь другое решение?
grishmanПользовательwww5 июля 201822:06#2
Delfigamer
> grishman
> А как ты себе представляешь другое решение?
Ну не передавать же мне объекту его же собственный указатель через публичный метод? А с этим механизмом shared_from_this объекты класса нельзя создавать на стеке, как минимум. Другое решение - это использовать raw-указатели, но ведь у современных программистов это моветон.

П.С.
Если shared_from_this - это действительно единственный способ, то не понимаю зачем вообще нужен этот несчастный С++, когда уже есть C# с автоматической сборкой мусора, не требующего такого говнодизайна - по сути ручной сборки мусора с кучей костылей и целым зоопарком умных указателей.

Правка: 5 июля 2018 22:26

DelfigamerПостоялецwww5 июля 201823:53#3
grishman
> А с этим механизмом shared_from_this объекты класса нельзя создавать на стеке,
> как минимум.
Разве? Почему?

grishman
> Другое решение - это использовать raw-указатели, но ведь у современных
> программистов это моветон.
Почему?

grishman
> не понимаю зачем вообще нужен этот несчастный С++, когда уже есть C# с
> автоматической сборкой мусора
tl;dr C++ нужен тогда, когда есть жёсткие ограничения на память, на время выполнения или нужно работать напрямую с оборудованием компьютера. Например - в ядре игрового движка, где нужно отрендерить сцену, посчитать физику, собрать ввод с контроллеров и связаться с сервером и при этом всё успеть за 16мс и уложиться в несколько мегабайт.

Именно. Отличие между автоматическими, автоматизированными и ручными системами состоит в том, что автоматические не требуют участия человека, в ручных - вся работа выполняется человеком, а в автоматизированных - некоторые процессы исполняются машиной, но для их запуска и управления всё равно требуется непосредственное участие человека.
C# - это, как ты правильно заметил, автоматический язык. Учёт времени жизни объектов и освобождение ресурсов совершенно не требуют какого бы то ни было вмешательства человека. Даже если ты ничего не сделаешь - виртуальная машина всё равно автоматически обнаружит ушедшие из видимости объекты и автоматически их уничтожит.
Ручной язык - это Си. Вот там все операции действительно делаются вручную - если ты не запишешь вызов функции явно, она не будет вызвана. Как ни странно, у этого подхода есть свои преимущества, в первую очередь - это быстродействие. Тогда как в автоматическом языке выполнение программы требуется периодически останавливать, чтобы сборщик мусора смог проанализировать текущее состояние программы и найти потерянные объекты; в ручном языке уничтожаются строго те объекты, о которых указал программист, строго в тех местах, где указал программист.
C++ - это автоматизированный язык. Однин из фундаментальных принципов языка - "ты не платишь за то, что не используешь". Как следствие - если требуется какая-то функциональность, её необходимо заказать явно в коде. Однако, когда заказ сделан - это позволяет языку расставить по коду дополнительные операции для поддержки этой функциональности. В умелых руках, это позволяет достичь уровня автоматизации, сравнимого с полностью автоматическими языками, при этом не теряя контроля над происходящим в программе.
Главный пример автоматизации в плюсах - это RAII. Объекты в плюсах можно настроить так, чтобы при их создании и уничтожении автоматически производились какие-то дополнительные действия.
Например - std::unique_ptr позволяет автоматически уничтожить объект, расположенный в куче, в момент уничтожения самого указателя. С одной стороны - время жизни указателя поддаётся точной настройке. С другой - значительно снижается риск пропустить уничтожение динамического объекта, на который ссылается этот указатель.
В целом - при правильном применении C++ предоставляет возможность оптимизировать программу до такого же уровня, какой доступен в Си, при этом не жертвуя безопасностью и выразительностью исходного текста программы.

Есть у плюсов и недостаток. Этот недостаток заключается в словах "при правильном применении" - кресты очень легко применить неправильно, и тогда программа соберёт все недостатки контроля и автоматизации - программа будет дырявой, как на Си, и медленной, как на Шарпе. Поэтому, входить в кресты рекомендуется, только уже имея хороший опыт использования нескольких других языков, например - набор из того же C#, Python, Scheme и PHP.

Правка: 5 июля 2018 23:55

*Lain*Постоялецwww6 июля 20181:13#4
grishman
> shared_from_this - это действительно единственный способ
https://www.boost.org/doc/libs/1_60_0/libs/smart_ptr/intrusive_ptr.html
получаем смартпоинтер из любого голого указателя
Blew_zcПостоялецwww6 июля 20181:38#5
Delfigamer
Эко тебя бомбануло.
SuslikМодераторwww6 июля 20182:01#6
grishman
в случае gui-виджетов, хранение shared_ptr ссылки на родителя не просто неудобно, но и приведёт к циклическим ссылкам — родитель не сможет удалиться, пока у него есть дети, дети не смогут удалиться, пока у них есть родитель. я считаю, правильнее сделать так, что при удалении родителя он автоматически удаляет всех детей. то есть родитель хранит std::unique_ptr'ы на детей, а дети хранят raw pointer, weak pointer или & ссылку на родителя.

Правка: 6 июля 2018 2:02

DimichПостоялецwww6 июля 20183:00#7
Это в qt и гтк так?
DelfigamerПостоялецwww6 июля 20183:01#8
Blew_zc
Напротив, мне показалось, что у ОПа просто неправильное впечатление из-за неопытности, вот и написал.
Зато в следующий раз, когда кто-нибудь опять начнёть ругать кресты - достаточно будет только скопировать цитату, и опционально выделить жирным строчку "это не язык плохой, а у автора руки кривые".

Suslik
Судя по коду в нуле, ОП так и хочет сделать; и подгорает от того, что умный указатель нельзя просто получить из объекта, нужно сначала написать "я хочу получить умный указатель из этого объекта".

*Lain*
> intrusive_ptr
По сути, std::enable_shared_from_this - это он и есть, плюс со встроенной тыквой на случай, если сильные ссылки закончатся раньше слабых.

SuslikМодераторwww6 июля 20183:47#9
Delfigamer
> Судя по коду в нуле, ОП так и хочет сделать; и подгорает от того, что умный
> указатель нельзя просто получить из объекта, нужно сначала написать "я хочу
> получить умный указатель из этого объекта".
нет. я предлагаю так:
void Control::AddChild()
{
  this->children.emplace_back(std::make_unique<Control>(this)); //опционально можно *this, чтоб передать по ссылке
}

умных указателей на себя вообще нет. ребёнок не может существовать без родителя, потому что при удалении родителя удаляются все дети.
EugeneУчастникwww6 июля 20186:37#10
Delfigamer
Не забудь про тыкву с конструктором.
DelfigamerПостоялецwww6 июля 20187:01#11
Eugene
> Не забудь про тыкву с конструктором.
???
DelfigamerПостоялецwww6 июля 20187:14#12
Лол, и правда тыква.
Стало быть, если нужен умный this прямо в конструкторе - придётся делать настоящий интрузивный счётчик.
WraithПостоялецwww6 июля 20187:26#13
grishman
>Пока нашел только такую дичь, от которой стало не по себе.
А как ты хотел? Только вприглядку что ли? Нет, если уж взялся за shared_ptr, не жалуйся, что все эти тентакли теперь в тебе, прямо во всей иерархии.
=A=L=X=Постоялецwww6 июля 20187:28#14
Delfigamer
> По сути, std::enable_shared_from_this - это он и есть

Интрузивность решает кучу проблем, например можно спокойно миксовать код с сырыми указателями и смартами вообще не задумываясь. Кроме того выделение смарта становится zero cost by nature, в отличие от шареда где начинаются пляски с бубном вокруг этого в виде make_shared. В общем я бы рекомендовал интрузивы везде где можно.
Если забить на всякие const-correctness, то реализацию можно сделать в пару десятков строк:

+ Показать

Страницы: 1 2 3 4 5 6 Следующая »

/ Форум / Программирование игр / Общее

2001—2018 © GameDev.ru — Разработка игр