Страницы

Поиск по вопросам

среда, 5 февраля 2020 г.

Определение объектов в C++

#cpp #классы #объекты #стек


Добрый день, интересует такой вопрос, по поводу определения объектов в С++. Насколько
я знаю объекты можно определять, как в стеке так и в куче. Знаю, что в стеке доступ
к объектам будет быстрее, но если нужно будет запрашивать большое количество памяти,
то нужно будет определять его в куче. Это в принципе все, что я знаю об этом. Хотелось
бы услышать внятный ответ, когда и в каких ситуациях предпочтительнее тот или иной способ.
    


Ответы

Ответ 1



Это в принципе все, что я знаю об этом. Хотелось бы услышать внятный ответ, когда и в каких ситуациях предпочтительнее тот или иной способ. Введем для этого пояснения такое понятие, как время жизни объекта (object lifetime). Будем считать, что объект начинает жизнь тогда, когда под него выделилась память и завершилась его инициализация. Всякие отводы, тонкости и закавыки рассматривать не будем. Объект умирает, когда память им занимаемая была освобождена или деструктор (если он есть и не тривиальный) объекта был вызван. Итак, для начала рассмотрим коротенько четыре "времени хранения" (storage duration). Статическое время хранения (static storage duration) - всё статическое живет от момента создания до самого конца программы. Потоковое время хранения (thread storage duration) - всё потоковое живет от момента создания до конца потока в котором создано. Автоматическое время хранения (automatic storage duration) - всё автоматическое живет от момента создания до конца блока в котором оно было создано. Динамическое время хранения (dynamic storage duration) - всё динамическое живет от момента создания до того момента, пока его явно не прихлопнут. Соответственно уже отсюда можно сделать вывод что нам необходимо. A. Если объект должен жить всю программу (ну, почти), то варианта два: Использовать объект с потоковым временем хранения, ежели у нас имеется один, живущий всю программу поток. Использовать объект с статическим временем хранения. Еще вариант, использовать динамический объект, но для его корректного уничтожения придется либо в какой-то из функций его явно уничтожить, что как бы уже подразумевает, что объект живет меньше чем статические объекты, либо же в деструкторе одного из статических объектов уничтожить и наш динамический объект, только вот получается, что нам для этого нужен статический объект, так что такой вариант не рассматриваем. Вариант не уничтожать его совсем - система прихлопнет память, рассматривать не будем, т.к. для объектов не будет вызван деструктор, а мы рассматриваем общее для всех объектов, а не отдельных их "видов". Так что для "чистоты эксперимента" подобные варианты мы не рассматриваем. Также выбросим из повествования временные объекты. B. С потоковыми объектами, практически также, как и со статическими, только в масштабах потока, так что расписывать не буду, ибо и так ясно. C. Если нам нужен объект, который должен быть уничтожен после выхода из блока, в котором создался, то варианта два: Использовать автоматический объект. Использовать динамический объект, но при этом придется вручную его создавать и уничтожать. D. Если нам необходимо, чтобы объект, созданный в блоке жил до самого конца программы (или потока),то вариант у нас один: Сделать его статическим объектом, ну или потоковым, если речь о потоке. С динамическим объектом та же фигня, что и в прошлый раз - до конца такое не доживет, либо уничтожится не правильно (в общем случае). E. Если нам необходимо, чтобы объект жил после выхода из блока в котором создан, но мы не знаем до какого времени он нам понадобится и, жить ему всю программу не нужно, то здесь вариант тоже один: Динамический объект. Теперь по каждому пункту отдельно. A. Потоковый или статический? А смотрим на программу. У нас планируется всего один поток? Если да, то нефиг пытать потоковый класс памяти. Если же потоков может быть несколько, то у каждого потока должна быть своя такая переменная? Если да, то потоковый берем, если нет - статический. B. см. предыдущий пункт. C. Автоматический или динамический? Объекты маленькие, их количество известно и они точно влезут в стек (без фанатизма)? Если да то использовать автоматические объекты или динамические зависит от хотелок разработчика и здравого смысла. Если не нужна динамика, то нафиг заниматься ручной работой? Но если очень хочется, то можно хоть каждый int делать динамическим. Если же объекты тяжелые и не хочется на них тратить стек, или же нам неизвестно конечное количество одновременно живущих элементов, то тут только динамические объекты прокатят. Вариант "создам здоровый массив на все случаи жизни" здесь не прокатит, т.к. выше оговорено, что конечное количество одновременно живущих объектов неизвестно и, соответственно, оно всегда будет равно sizeof(mySuperArray)/sizeof(*mySuperArray) + 1. D. Всё как и прежде - смотрим на потребности в каждом потоке. E. Без вариантов. В программах, чаще всего, встречается смесь из всего высказанного выше в разных пропорциях и сочетаниях. Вот такая абсолютно бесполезная портянка, т.к. она всё равно не покрывает всего и вся и не является истиной в последней инстанции.

Ответ 2



Стек ограничен, и время жизни автоматических объектов заканчивается, когда выполнение выходит из блока, где объект был объявлен. Поэтому, когда требуется контролировать время жизни и иметь "неограниченный" размер данных, приходится использовать кучу. Доступ быстрее в стеке не будет, так как память физически та же самая, что и для объектов в куче. Другое дело, что данные могут быть в кэше, где скорость доступа выше, но это характерно для любых данных, независимо от места их объявления. В давние времена пытались оптимизировать добавляя ключевое слово register к объявляемой переменной. Сейчас это уже не актуально. Более того, начиная с c++17 это слово зарезервировано и не используется.

Ответ 3



Таки да (!), доступ к объектам в куче будет медленнее. Так как в случае создания объектов в куче еще добавляется время, необходимое для выделение и освобождение памяти в куче. Если объект в программе один и создается этот объект один раз, то различие невелико. А если в куче приходится во время работы создавать и удалять МНОГО объектов, то время на выделение объекта в куче становится существенным (по сравнению с временем на выделение объекта в стеке). В стеке память под объекты в большинстве современных архитектур выделяются одной машинной командой. А чтобы выделить память под объекты в куче, надо выполнить целую подпрограмму. UPD1: так а почему именно доступ(!) будет медленнее? Я бы понял создание/удаление объекта. Но доступ то... Если надо в программе ПОСТОЯННО создавать и удалять объекты, то время ДОСТУПА включает и время на создание/удаление объекта. ИБО очевидно, что не создав объект, доступа к нему не получишь. Собственно же ДОСТУП, конечно, в СОВРЕМЕННЫХ архитектурах персоналок и мобильников не отличается по времени. Однако были и есть архитектуры (например приснопамятная однокристалка от Интел пятьдесят первой серии) в которых даже и собственно ДОСТУП к памяти значительно отличается по времени от ДОСТУПА к стеку. UPD2: Опа-на. Пока я отвечал, комментарий на который я отвечал куда-то делся. :-) Чудны дела Твои Господи. :-)

Комментариев нет:

Отправить комментарий