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

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

Страницы: 1 2 3 4 5 6 Следующая »
DelfigamerПостоялецwww6 июля 201822:27#45
Kartonagnick
> см выше.
Выше только Снуп Дог. Ты делаешь это из-за Снуп Дога?
grishmanПользовательwww6 июля 201823:43#46
Delfigamer
> Ух нихрена себе быстро.
Читай раздел Allocating Memory, там объясняется как аллокация (выделение куска памяти) работает в С#.
Среда выполнения С++ предоставляет обычную (неуправляемую) кучу, где для того чтобы выделить кусок памяти через оператор new, необходимо найти свободный блок памяти в куче, произвести определенные манипуляции с ним, и наконец обновить список доступных блоков памяти. Более того, с течением времени в такой неуправляемой куче может начаться фрагментация, которая понижает скорость аллокации (поиск свободного блока памяти в куче становится дольше).
В среде выполнения C#, блок памяти под новый объект всегда находится на вершине кучи. Отсюда и скорость аллокации получается как в стеке. Это обеспечивается тем, что после удаления объектов из кучи (происходит только при устранении утечек памяти, когда потеряны все ссылки на критическое количество объектов) - сборщик мусора выполняет так называемое уплонение кучи (дефрагментацию).
То на что ты ссылаешься цитатой - из раздела Releasing Memory, и является описанием того, какие эффекты могут присходить при сборке мусора. К аллокации памяти в куче это отношения не имеет - она по прежнему остается гораздо быстрее чем в Си или С++.

Kartonagnick
> grishman
> > Порядок вызова конструкторов при наследовании напомнить?
> хорош тупить.
ты уже разобрался почему виртуальное наследование не работает в конструкторах? Клацни по ссылке "Пруф", там пример в онлайн компиляторе запускается.

Правка: 6 июля 2018 23:47

ardruПостоялецwww7 июля 20180:14#47
grishman
> Среда выполнения С++ предоставляет

Да хрен не неё! Есть куча библиотек. Погуглите memory pool C++
Среда выполнения С++ не даёт никакого выигрыша в скорости выполнения, а нужна лишь для поддержки стандартных библиотек и является "золотой серединой".

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

Правка: 7 июля 2018 0:19

grishmanПользовательwww7 июля 20180:25#48
ardru
> Можно какой угодно алгоритм уборки мусора использовать в С++, в зависимости от
> контекста задачи. Можно просто память выделить один раз и не освобождать
> вообще.
Я говорил об аллокации в куче. Конечно можно навелосипедить свой аллокатор памяти, и вручную вызывать деструктор. Но как это будет выглядеть со стороны? Запускатеся приложение, и сходу жрет большой кусок оперативной памяти без явных на то причин?
ardruПостоялецwww7 июля 20180:37#49
grishman
> Я говорил об аллокации в куче. Конечно можно навелосипедить свой аллокатор
> памяти, и вручную вызывать деструктор. Но как это будет выглядеть со стороны?
> Запускатеся приложение, и сходу жрет большой кусок оперативной памяти без явных
> на то причин? А если приложение свернулось и нужно временно освободить
> захваченные ресурсы для нормальной работы остальных приложений?

Это всё какие-то отвлечённые темы. Если это игра - то никого не должно удивить что она жрёт большой кусок памяти.
И потом, основные расходы памяти обычно - текстуры, которые вообще в видеопамяти хранятся. Можно их оттуда удалить при свёртывании и загрузить при восстановлении окна...
Ну что там ещё может занять "большой кусок памяти"?

Правка: 7 июля 2018 0:39

WraithПостоялецwww7 июля 20186:38#50
Delfigamer
> Это не является особенностью enable_shared_from_this; это свойство присуще всем
> умным указателям - нельзя вызывать delete на указателе, полученном от стековой
> переменной.
Это как раз является особенностью shared_ptr, и добавлено это лишь в силу особенностей идиотской реализации shared_ptr, перекочевавшей туда из бузда, -  потому что объект, на который не указывает ни один shared_ptr, не имеет shared_section.

grishmanПользовательwww7 июля 201811:24#51
ardru
> Это всё какие-то отвлечённые темы. Если это игра - то никого не должно удивить
> что она жрёт большой кусок памяти.
Ты прав, в целом С++ быстрее C#, хоть и дается это более высокой ценой.
Спасибо всем за обсуждение вопроса и помощь в поиске решений. Вариант от Suslik мне нравится больше всего.
+ замер скорости C++/C# на небольшом примере

Правка: 7 июля 2018 13:29

dayllengerПользовательwww7 июля 201815:29#52
grishman
> Так откуда базовому конструктору узнать о переопределенных методах в производном классе?
> Вот и выходит что полиморфизм в конструкторах не работает.
Delfigamer
> Он не может знать о производном классе, потому что производного класса на этот
> момент ещё не существует.
Я извиняюсь за оффтоп, но меня это просто поразило. В языке D, например, виртуальные функции работают всегда.
Специально заглянул в C++ Gotchas, и действительно: объект в базовом конструкторе ещё не имеет типа производного класса, а потому вызовется не та функция, которую ожидаешь. Возникает впечатление, будто производный класс "ещё не существует", хотя это абсурд.
"Замечательное" языковое решение.
BUzerПостоялецwww7 июля 201815:40#53
dayllenger
Нуу… А иначе получилось бы, что виртуальные функции у объекта вызываются до того, как вызвался его конструктор, что довольно абсурдно.
=A=L=X=Постоялецwww7 июля 201815:54#54
dayllenger
> Возникает впечатление, будто производный класс "ещё не существует", хотя это
> абсурд.
Это не впечатление, а совершенно верное наблюдение - С++ исповедует такую концепцию, что не существует никаких "занулённых" состояний у полей объекта по умолчанию - инициализация производится конструкторами и только ими. При этом получается, что как у матрёшки чтобы запустить конструктор наследника надо чтобы сперва отработал конструктор предка. И тут всё просто - пока конструктор наследника не запустится поля добавленные в его классе физически еще не проинициализированы никак. Ни нулями ни дефолтами - просто мусорные байты лежат по их адресам. В связи с этим матрёшка создания объекта выглядит следующим образом:
- сперва вызываются конструкторы полей базового класса, и только после того как они все создадутся...
- затем вызывается тело конструктора базового класса написанное программистом - в нём уже можно безопасно трогать поля базового класса
- затем вызываются конструкторы полей класса-наследника
- и далее тело конструктора наследника - опять таки оно может трогать и поля наследника и поля базового класса.
Именно в связи с этой схемой и придумали списки инициализации в конструкторах - ведь если у поля конструктор с параметром, то вызвать его из конструктора как раз не получится - в конструкторе поле уже должно быть проинициализировано. Значит конструктор надо как то вызвать еще до тела конструктора - за это и отвечают списки инициализации.

Ну и вот - а теперь очень простой вывод - если бы таблицы виртуальных методов были заполнены методами наследников уже в конструкторе базового класса, то через них получилось бы что можно дотянуться до еще несконструированных переменных - а это полное UB.
Именно поэтому C++ так принципиально стоит на этом моменте - это the way it's meant to be constructed.
В других языках проблема решается обычно тем, что еще до конструкторов поля объекта заливаются какими то дефолтными валидными данными, что можно в них тыкать даже не дожидаясь когда отработают конструкторы предков, это не вызовет UB моментально. С++ не такой.

Поэтому как бы там адепты RAII не ворчали, но virtual Init/Done нередко спасают от переголовы.

Правка: 7 июля 2018 15:56

grishmanПользовательwww7 июля 201815:58#55
BUzer
> Нуу… А иначе получилось бы, что виртуальные функции у объекта вызываются до
> того, как вызвался его конструктор, что довольно абсурдно.
Я думаю можно было бы реализовать единый конструктор для всех классов в иерархии наследования, и строить объект не по частям (от базового к производным), а за один раз. Тогда бы полиморфизм в конструкторах работал бы, а сами конструкторы были как инициализирующие методы.
В C# в этом плане также как в С++.

Правка: 7 июля 2018 16:03

dayllengerПользовательwww7 июля 201816:33#56
=A=L=X=
Логичная схема в контексте C++, но громоздская. Спасибо за объяснение.
Значит, невозможно в конструкторе базового класса писать обобщённый код, даже если ты вызываешь этот конструктор явно. Допустим, гипотетичeски, SomeWidget в конструкторе делает addChild, но его реализация и контейнер для дочерних виджетов находятся у унаследованного класса и могут быть какими угодно.
=A=L=X=Постоялецwww7 июля 201816:42#57
dayllenger
> контейнер для дочерних виджетов

Вот всякие GUI/виджеты/компоненты/дочки/матери - первейшие кандидаты на ООП - а там неминуемо появляются всякие потребности в serialise/deserialise, createByClassName, clone и т.п. - а это всё действительно намного проще реализовать по схеме virtual void Init, чем пытаться соблюдать RAII до последней капли крови.

DelfigamerПостоялецwww7 июля 201817:19#58
Wraith
> Это как раз является особенностью shared_ptr, и добавлено это лишь в силу
> особенностей идиотской реализации shared_ptr, перекочевавшей туда из бузда, -
> потому что объект, на который не указывает ни один shared_ptr, не имеет
> shared_section.
Мне тебя тынкуть носом в operator delete и все следующие из него прелести; или ты сам догадаешься?
WraithПостоялецwww8 июля 20181:38#59
Delfigamer
> Мне тебя тынкуть носом в operator delete и все следующие из него прелести; или ты сам догадаешься?
Хех, ну давай, тыкни что ли.
Страницы: 1 2 3 4 5 6 Следующая »

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

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