C ++ Управление памятью - PullRequest
8 голосов
/ 26 августа 2008

В колледже я узнал, что вы всегда должны освобождать неиспользуемые объекты, а не то, как вы это делаете Например, структурирование вашего кода правильно и так далее. Существуют ли общие правила работы с указателями в C ++?

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

Ответы [ 8 ]

14 голосов
/ 26 августа 2008

Я работал со встроенной операционной системой Symbian, для которой была создана отличная система, полностью основанная на соглашениях разработчиков.

  1. Только один объект будет иметь указатель. По умолчанию это создатель.
  2. Право собственности может быть передано. Чтобы указать передачу права собственности, объект передается как указатель в сигнатуре метода (например, void Foo (Bar * zonk);).
  3. Владелец сам решит, когда удалять объект.
  4. Чтобы передать объект в метод только для использования, объект передается как ссылка в сигнатуре метода (например, void Foo (Bat & zonk);).
  5. Классы, не являющиеся владельцами, могут хранить ссылки (никогда не указатели) на объекты, которые им предоставляются, только когда они могут быть уверены, что владелец не уничтожит их во время использования.

По сути, если класс просто что-то использует, он использует ссылку. Если классу что-то принадлежит, он использует указатель.

Это работало прекрасно и было приятно пользоваться. Проблемы с памятью были очень редкими.

5 голосов
/ 26 августа 2008

Правила:

  1. По возможности используйте умный указатель . Boost имеет некоторые хороших .
  2. Если вы нельзя использовать умный указатель, null out Ваш указатель после удаления .
  3. Никогда не работайте там, где не разрешено использовать правило 1.

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

3 голосов
/ 26 августа 2008

Я бы добавил еще одно правило:

  • Не открывайте и не удаляйте объект, если с автоматическим объектом все будет в порядке.

Мы обнаружили, что программисты, которые являются новичками в C ++, или программисты, пришедшие с таких языков, как Java, похоже, узнают о новом и затем одержимо используют его, когда хотят создать какой-либо объект, независимо от контекста. Это особенно пагубно, когда объект создается локально внутри функции исключительно для того, чтобы сделать что-то полезное. Использование нового таким образом может отрицательно сказаться на производительности и может слишком легко привести к глупым утечкам памяти, когда соответствующее удаление будет забыто. Да, умные указатели могут помочь с последним, но это не решит проблемы с производительностью (при условии, что new / delete или эквивалент используется за кулисами). Интересно (ну, может быть), мы обнаружили, что удаление часто имеет тенденцию быть более дорогим, чем новое при использовании Visual C ++.

Часть этой путаницы также связана с тем фактом, что вызываемые ими функции могут принимать указатели или даже умные указатели в качестве аргументов (когда ссылки, возможно, будут лучше / понятнее). Это заставляет их думать, что им нужно «создать» указатель (многие люди думают, что это то, что делает новинка), чтобы иметь возможность передавать указатель на функцию. Понятно, что для этого требуются некоторые правила написания API, чтобы сделать соглашения о вызовах как можно более однозначными, что подкрепляется четкими комментариями, поставляемыми с прототипом функции.

2 голосов
/ 26 августа 2008

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

Иногда вам нужно размещать объекты динамически, но они будут использоваться только в течение определенного промежутка времени. Например, в предыдущем проекте мне нужно было создать сложное представление схемы базы данных в памяти - в основном сложный циклический граф объектов. Однако график был необходим только на время соединения с базой данных, после чего все узлы могли быть освобождены за один раз. В этом сценарии хорошим примером для использования является то, что я называю «идиома локального GC». Я не уверен, имеет ли оно «официальное» имя, поскольку я видел его только в своем коде и в Какао (см. NSAutoreleasePool в справочнике Apple по какао).

В двух словах, вы создаете объект "сборщик", который сохраняет указатели на временные объекты, которые вы выделяете с помощью new. Обычно он привязан к некоторой области в вашей программе, либо к статической области (например, как объект, выделенный в стеке, который реализует идиому RAII), либо к динамической области (например, привязанной к времени жизни соединения с базой данных, как в мой предыдущий проект). Когда объект "сборщик" освобожден, его деструктор освобождает все объекты, на которые он указывает.

Также, как и DrPizza, я считаю, что ограничение не использовать шаблоны слишком жесткое. Тем не менее, проделав большую разработку для старых версий Solaris, AIX и HP-UX (совсем недавно - да, эти платформы все еще живы в Fortune 50), я могу сказать вам, что если вы действительно заботитесь о переносимости, вы следует использовать шаблоны как можно меньше. Тем не менее, использование их для контейнеров и умных указателей должно быть в порядке (у меня это сработало). Без шаблонов описанная мной техника более болезненна для реализации. Для этого потребуется, чтобы все объекты, управляемые «сборщиком», происходили из общего базового класса.

2 голосов
/ 26 августа 2008

В общем случае (управление ресурсами, где ресурс не обязательно является памятью), вам необходимо ознакомиться с шаблоном RAII . Это одна из самых важных частей информации для разработчиков на C ++.

1 голос
/ 26 августа 2008

G'day,

Я бы предложил прочитать соответствующие разделы «Эффективного C ++» Скотта Мейерса. Легко читается, и он рассказывает о некоторых интересных хитростях, чтобы поймать неосторожных.

Меня также заинтриговало отсутствие шаблонов. Так что нет STL или Boost. Ничего себе.

Кстати, заставить людей договариваться о конвенциях - отличная идея. Как заставить всех договориться о соглашениях по ООД. Кстати, в последнем издании Effective C ++ нет прекрасной главы о соглашениях OOD, которую жаль в первом издании, например. такие соглашения, как публичное виртуальное наследование всегда моделируют отношения "isa".

Rob

0 голосов
/ 26 августа 2008

вы можете получить все из некоторого базового класса, который реализует интеллектуальные функции, такие как указатель (используя методы ref () / unref () и счетчик.

Все точки, выделенные @Timbo, важны при разработке этого базового класса.

0 голосов
/ 26 августа 2008
  • Когда вам нужно использовать управление памятью вручную, убедитесь, что вы звоните удалить В то же самое область действия / функция / класс / модуль, который когда-либо применяется первым, например ::100100
  • Пусть вызывающая функция выделяет память, которую она заполняет, не возвращать новые указатели.
  • Всегда вызывайте delete в том же exe / dll, который вы вызывали в new, потому что иначе у вас могут возникнуть проблемы с повреждениями кучи (разные несовместимые библиотеки времени выполнения).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...