Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

Правила:

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

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

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

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

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

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

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

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

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

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

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

Добрый день,

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

Я также заинтригован отсутствием шаблонов.Так что никакого STL или Boost.Ух ты.

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

Роб

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top