2008-08-26 2 views
8

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

В настоящее время я не могу использовать boost. Я должен придерживаться чистого C++, потому что используемая среда запрещает использование дженериков.

+0

Жаль, что это так давно. Мне бы хотелось услышать объяснение, почему вы не можете использовать (в частности) дженерики. – jmucchiello 2009-04-27 01:43:55

+0

Из документации рамки: Не используйте шаблоны. Они не переносимы в разные операционные системы, особенно в том случае, если они поддерживаются компиляторами и редакторами ссылок. В настоящее время все, что я могу сказать об этом – 2009-04-27 11:13:59

+0

Шаблоны были хорошо поддержаны в разных операционных системах в 2009 году, при условии, что у этих ОС практически нет доступных компиляторов. Любой, кто пишет структуру, должен был придумать некоторые фактические доказательства своей претензии. – 2017-01-17 01:15:20

ответ

14

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

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

В принципе, если класс просто использует что-то, он использует ссылку. Если класс владеет чем-то, он использует указатель.

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

5

Правила:

  1. Везде, где это возможно, использовать smart pointer. У Boost есть good ones.
  2. Если вы не можете использовать умный указатель, null out your pointer after deleting it.
  3. Никогда не работать в любом месте, что не позволит вам использовать правило 1.

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

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

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

0

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

Все точки подсвечивается @Timbo имеют важное значение при разработке базового класса.

1

G'day,

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

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

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

Роб

3

Я хотел бы добавить еще одно правило здесь:

  • Do не новый/удалить объект, когда автоматический объект будет делать только штрафом.

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

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

2

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

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

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

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

Смежные вопросы