Как выбирать где создавать экземпляры класса, в динамической памяти или на стеке?
В ходе разработки достаточно большого проекта, я столкнулся с тем, что экземпляры классов у меня созданы все как-то хаотически: что-то в динамической памяти, что-то в стеке. Я пришел к тому, что у меня нет однозначных правил когда и как я создаю объект класса и это сеет некоторый бардак.
Единственное правильно, которое я обнаружил: в main-e я выделяю объекты в стеке(только если они не синглтон, как конфиг например)(но их там собственно не очень много, менее 5 штук - конфиг, работа основного алгоритма, запись результатов в бд. Вот уже внутри алгоритма и бд полнейший хаос). Можно добавить то, что если объект класса мне нужен только в пределах метода, то тоже не выделяю динамически(хотя наверное, если метод вызывается n раз стоило бы данный объект хранить в классе).
В общем я пришел к выводу, что я не знаю как создавать объекты и где их хранить и в каких случаях, и в этом смысле у меня отсутствует система как в проекта, так и в голове.
Подскажите, есть ли какие-то правила по этой теме или как вообще разобраться в этом всём?
Ответы (2 шт):
Ответ на ваш вопрос тянет на целую статью из нескольких листов, не считая массу ожидаемых обсуждений. Если объекты могут быть кандидатом на удаление в данной области видимости, то создайте динамически, или если для их количества в стеке может место не хватать. Например многие пользуются только стандартным вектором std::vector, или советуют его при любых обстоятельствах. Но вы должны смотреть для чего храните эти объекты, как будете ими пользоваться, какие действия будут выполняться с контейнером и так далее(точно так же, как и организовывают любое дело).
Иногда(для примера) может быть уместно создать свою собственную тривиальную хэш_таблицу, чем пользоваться стандартным. Существующий любой способ хранения имеет свои преимущества и недостатки, но если не нужно будет выращивать контейнер или удалять некоторые объекты по ходу, то логично их хранить статически в таких, как std::valarray std::array..., в собственноручно написанном или стандартном, но точно не в векторе или других контейнерах, которые используют динамическую память, просто потому что это дороже и не специфично для данного метода. Нет общих правил дизайна и архитектуры _ каждому свое...
Всегда на стеке, если нет какой-то конкретной причины использовать кучу.
Возможные причины:
- Это массив переменного размера - в стандартном С++ их нельзя создать на стеке.
- Объект должен пережить выход из функции, где был создан. Причем пережить в своем оригинальном виде, а не как
returnутая копия. - Объект слишком большой. (Несколько килобайт? При размере стека в единицы мегабайт.)
- ...?
И как правильно пишет @StanislavVolodarskiy, в вашем коде не должно быть new и delete. Это низкоуровневые инструменты для авторов контейнеров и умных указателей: std::vector, std::unique_ptr и подобных. Используйте их вместо new и delete.