В колледже я узнал, что вы всегда должны освобождать неиспользуемые объекты, но не то, как вы это делаете на самом деле. Например, правильное структурирование кода и так далее. Есть ли какие-то общие правила обработки указателей в C++?
В настоящее время мне не разрешено использовать ускорение. Я должен придерживаться чистого C++, потому что используемый мной фреймворк запрещает любое использование дженериков.
Из документации фреймворка: Не используйте шаблоны. Они не переносятся в другие операционные системы, особенно в том, как они поддерживаются компиляторами и редакторами ссылок. На данный момент это все, что я могу сказать об этом.
В 2009 году шаблоны прекрасно поддерживались в разных операционных системах, при условии, что в указанных операционных системах для них были недоступны компетентные компиляторы. Любой, кто пишет фреймворк, должен был представить реальные доказательства своего утверждения.
@KonradRudolph: Официальный ответ на это: Они не переносятся в другие операционные системы, особенно в том, как они поддерживаются компиляторами и редакторами ссылок.
@AlexanderStolz: Это неправильно. Я имею в виду, что C++ в целом несовместим с разными операционными системами (большинство платформ имеют четкий и четко определенный C ABI, а не C++, особенно если вы вдавитесь в детали, такие как представления виртуального наследования и т. д.). В этом плане шаблоны ничего не меняют; созданные шаблоны - это просто классы с забавными именами. Несколько лет назад поддержка компилятора была насущной проблемой, но в наши дни нет оправдания тому, чтобы не использовать g ++ 4.x или VC++ 2005/2008, которые более чем достаточно хороши для любого нормального использования.





Правила:
Если кто-то запрещает правило 1, помните, что если вы захватите чужой код, измените имена переменных и удалите уведомления об авторских правах, никто этого не заметит. Если только это не школьный проект, где они действительно проверяют такие махинации с помощью довольно сложных инструментов. См. Также этот вопрос.
-1 для обнуления. Я не буду обсуждать это здесь, но это хорошая практика нет. Если код написан достаточно хорошо, в этом нет необходимости, так как вы не должны удалять, пока не убедитесь, что больше не существует ссылок / указателей Другой на ваш выделенный блок памяти.
Я работал со встроенной ОС Symbian, в которой для этого была создана отличная система, полностью основанная на соглашениях разработчиков.
По сути, если класс просто что-то использует, он использует ссылку. Если класс чем-то владеет, он использует указатель.
Это прекрасно сработало, и им было приятно пользоваться. Проблемы с памятью были очень редкими.
Я бы использовал std :: auto_ptr, чтобы показать, что судно-владелец передается (а не указатель RAW). Предположительно, вы уже сохраняете в интеллектуальном указателе, если ожидается единоличное владение, std :: auto_ptr идеально подходит.
ОП сказал, что он не может использовать дженерики, что, по-видимому, исключает любой тип интеллектуального указателя.
Не будет ли дамп ядра приложения, если объект, на который указывает ссылка, удален по ошибке? Если бы это был указатель, мы могли бы проверить наличие null (при условии, что средство удаления установит его на null).
@balki Может; это может и не быть; это может вызвать дождь из тостеров с неба: это UB. Но Сандер сказал, что ссылки используются только в том случае, если есть гарантия, что они не станут свисающими, так что это проблема качества кода. И что еще более важно, указатели ничем не лучше: удаление объекта другим объектом не устанавливает копию указателя на nullptr наблюдателем, поэтому его нельзя проверить на достоверность больше, чем можно по ссылке (читайте: nullptrness - это свойство адреса, а не данных по этому адресу) ... если каждый наблюдатель ptr не зарегистрирован ссылкой с владельцем для последующего обновления или чего-то запутанного
В общем случае (управление ресурсами, когда ресурс не обязательно является памятью) вам необходимо знать Шаблон RAII. Это одна из самых важных сведений для разработчиков C++.
вы можете получить все из некоторого базового класса, который реализует интеллектуальные указатели, такие как функциональность (используя методы ref () / unref () и счетчик.
Все моменты, выделенные @Timbo, важны при разработке этого базового класса.
Доброго времени суток,
Я бы посоветовал прочитать соответствующие разделы «Эффективного C++» Скотта Мейерса. Легко читать, и он раскрывает некоторые интересные подводные камни, чтобы поймать неосторожных.
Еще меня заинтриговало отсутствие шаблонов. Так что никаких STL или Boost. Вау.
Кстати, заставить людей соглашаться на условности - отличная идея. Как и заставить всех договориться об условных обозначениях для OOD. Кстати, в последней редакции Effective C++ нет отличной главы о соглашениях о OOD, которые были в первой редакции, что очень жаль, например такие соглашения, как публичное виртуальное наследование всегда моделируют отношения «isa».
Роб
Я бы добавил сюда еще одно правило:
Мы обнаружили, что программисты, которые плохо знакомы с C++, или программисты, пришедшие с таких языков, как Java, похоже, узнают о новом, а затем одержимо используют его, когда хотят создать какой-либо объект, независимо от контекста. Это особенно пагубно, когда объект создается локально внутри функции исключительно для того, чтобы делать что-то полезное. Использование new таким образом может отрицательно сказаться на производительности и упростить создание глупых утечек памяти, когда соответствующее удаление будет забыто. Да, интеллектуальные указатели могут помочь с последним, но это не решит проблем с производительностью (при условии, что new / delete или эквивалент используется за кулисами). Интересно (ну, может быть), мы обнаружили, что удаление часто бывает дороже, чем новое при использовании Visual C++.
Некоторая путаница возникает также из-за того, что функции, которые они вызывают, могут принимать указатели или даже интеллектуальные указатели в качестве аргументов (когда ссылки, возможно, были бы лучше / яснее). Это заставляет их думать, что им нужно «создать» указатель (многие люди, кажется, думают, что это именно то, что делает new), чтобы иметь возможность передавать указатель на функцию. Ясно, что для этого требуются некоторые правила написания API, чтобы сделать соглашения о вызовах как можно более однозначными, которые подкрепляются четкими комментариями, поставляемыми с прототипом функции.
Принятие из Ниццы "Это заставляет их думать, что им нужно" создать "указатель (многие люди, кажется, думают, что это именно то, что делает new), чтобы иметь возможность передать указатель на функцию.)" Может быть, но я думаю, это потому, что большинство университетов сначала преподают Java. В Java вам нужно все «новое», и трудно избавиться от этой привычки, особенно когда два языка выглядят очень похожими, но на самом деле совершенно разными. Для настоящего удовольствия попробуйте работать с обоими одновременно!
В общем, избегайте выделения из кучи, если вам не нужно. При необходимости используйте подсчет ссылок для объектов, которые являются долгоживущими и должны использоваться совместно различными частями вашего кода.
Иногда вам нужно динамически размещать объекты, но они будут использоваться только в течение определенного промежутка времени. Например, в предыдущем проекте мне нужно было создать сложное представление схемы базы данных в памяти - в основном сложный циклический граф объектов. Однако граф был нужен только на время соединения с базой данных, после чего все узлы могли быть освобождены одним выстрелом. В таком сценарии хороший шаблон для использования - это то, что я называю «идиомой локального сборщика мусора». Я не уверен, есть ли у него «официальное» имя, поскольку это то, что я видел только в моем собственном коде и в Какао (см. NSAutoreleasePool в ссылке Apple на Какао).
В двух словах, вы создаете объект «сборщик», который хранит указатели на временные объекты, которые вы выделяете с помощью new. Обычно он привязан к некоторой области в вашей программе, либо к статической области (например, как выделенный стек объект, который реализует идиому RAII), либо к динамической (например, привязанной к времени жизни соединения с базой данных, как в мой предыдущий проект). Когда объект «сборщик» освобождается, его деструктор освобождает все объекты, на которые он указывает.
Также, как и DrPizza, я считаю, что запрет на использование шаблонов слишком суров. Однако, после большого количества разработок на старых версиях Solaris, AIX и HP-UX (совсем недавно - да, эти платформы все еще живы в Fortune 50), я могу сказать вам, что если вы действительно заботитесь о переносимости, вы следует как можно меньше использовать шаблоны. Однако использование их для контейнеров и интеллектуальных указателей должно быть нормальным (у меня это сработало). Без шаблонов описанную мной технику реализовать труднее. Это потребует, чтобы все объекты, которыми управляет «сборщик», были производными от общего базового класса.
Хотя идиома с локальным сборщиком мусора звучит хорошо, в этом нет необходимости. Ручное управление памятью не так уж и сложно.
Жаль, что это так старо. Мне бы хотелось услышать объяснение, почему вы не можете использовать (конкретно) дженерики.