Передовые методы управления собственными памятью Visual С++
===========================================================

Я старый программист на С# и программист на C (без динамического распределения памяти), но хотел бы немного узнать о программировании на Visual С++. Вопрос, который меня беспокоит, связан с управлением памятью на С++. В С# сборщик мусора заботится об управлении памятью, но на С++ необходимо установить некоторые правила относительно того, кто отвечает за освобождение выделенной памяти. У меня есть некоторые типичные сценарии из С#:

* Объект помещается в какой-либо контейнер. Кто несет ответственность за освобождение памяти. Что делать, если несколько классов имеют один и тот же объект?
* Factory. Мне нравится использовать иерархию классов, где родительский класс имеет метод создания дочерних объектов?
* Есть ли способ предложить вызывающему методу, чтобы возвращаемый объект находился в собственности вызываемого абонента.

Я хотел бы услышать хорошие советы об этом.

 

Если вы правильно напишете свой код, вам не придется беспокоиться об этом, по крайней мере, не напрямую. Для вас доступны библиотеки, которые управляют управлением памятью и другим управлением ресурсами для вас, полностью автоматически, так что вам не нужно.

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

Если вы динамически выделяете объект, используйте умный указатель для управления его временем жизни. Если вам не нужно делиться собственностью, вы можете использовать `std::unique_ptr`, который позволяет переносить право собственности с одного игрока на другого. Если вам нужно передать права собственности, вы можете использовать `std::shared_ptr`, который использует метод подсчета ссылок для поддержания совместного использования.

Существует два важных правила:

* **Если вам нужно написать `delete` в вашей программе на С++, код почти наверняка будет неправильным.** С++ обеспечивает автоматическое управление жизненным циклом для всех ресурсов, включая память, и вы должны воспользоваться из этого. Единственное место `delete` должно появиться в библиотечном коде, где реализуются контейнеры с ресурсами и потенциально в более редком, низкоуровневом коде.
* **Предпочитают обращаться к объектам, а не к указателям на объекты, где это возможно.** По возможности избегайте явного динамического распределения. С++ не похож на такие языки, как С# и Java, где большинство объектов создаются в куче. В С++ часто лучше создавать объекты в стеке (используя автоматические переменные) и возвращать их по значению.

Чтобы ответить на ваши конкретные сценарии:

>  Объект помещается в какой-то контейнер. Кто несет ответственность за освобождение памяти. Что делать, если несколько классов имеют один и тот же объект?
> 
> 
> 

 .i1a { width: 336px; height: 280px; }
 @media(min-width: 768px) { .i1a { width: 728px; height: 90px; } }
 @media(min-width: 992px) { .i1a { width: 360px; height: 300px; } }
 @media(min-width: 1083px) { .i1a { width: 728px; height: 90px; } }

 (adsbygoogle = window.adsbygoogle || []).push({});

Вы должны, по возможности, предпочесть хранить сами объекты в контейнере, а не указатели на объекты. Если вы по какой-то причине должны хранить указатели на объекты, вы должны использовать контейнер (например, `std::vector`) интеллектуальных указателей. Если контейнер имеет право владения динамически выделенными объектами, вы можете использовать `std::vector<std::unique_ptr<T>>`; если контейнер собирается передать права собственности на объекты, вы можете использовать `std::vector<std::shared_ptr<T>>`.

>   Factory. Мне нравится использовать иерархию классов, где родительский класс имеет метод для создания дочерних объектов?
> 
> 
> 

Это ничем не отличается от предыдущего сценария: если у вас есть дерево, довольно просто использовать `std::vector<T>` (или `std::vector<std::unique_ptr<T>>`, если вам нужны динамически выделенные дочерние элементы), чтобы иметь своих детей.

>  Есть ли способ предложить вызывающему методу, чтобы возвращаемый объект находился в собственности вызываемого абонента.
> 
> 
> 

Если объект принадлежит исключительно вызываемому лицу (например, в `std::unique_ptr`), вы можете вернуть этот умный указатель; это приведет к передаче права собственности вызывающему абоненту.

Если существует общий доступ к объекту (например, в `std::shared_ptr`), то возврат умного указателя сделает вызывающего абонента одним из владельцев; последний владелец отказывается от своей собственности (уничтожая или иным образом перезагружая свой `std::shared_ptr`, который владеет объектом) автоматически уничтожает объект.

 

Ответ Джеймса правильный. Однако он не упоминает имя той техники, которую он обсуждает. RAII - очень важная концепция управления памятью (и другим ресурсом) на С++. RAII означает, что инициализация ресурсов является инициализацией. Однако не позволяйте этому имени путать вас, потому что это немного вводит в заблуждение.

 .i2a { width: 336px; height: 280px; }
 @media(min-width: 768px) { .i2a { width: 728px; height: 90px; } }
 @media(min-width: 992px) { .i2a { width: 360px; height: 300px; } }
 @media(min-width: 1083px) { .i2a { width: 728px; height: 90px; } }

 (adsbygoogle = window.adsbygoogle || []).push({});

Википедия - хорошее место, чтобы начать читать:
[RAII в Википедии](http://en.wikipedia.org/wiki/RAII)