C++ Управление памятью

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

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

Жаль, что это так старо. Мне бы хотелось услышать объяснение, почему вы не можете использовать (конкретно) дженерики.

jmucchiello 27.04.2009 05:43

Из документации фреймворка: Не используйте шаблоны. Они не переносятся в другие операционные системы, особенно в том, как они поддерживаются компиляторами и редакторами ссылок. На данный момент это все, что я могу сказать об этом.

Alexander Stolz 27.04.2009 15:13

В 2009 году шаблоны прекрасно поддерживались в разных операционных системах, при условии, что в указанных операционных системах для них были недоступны компетентные компиляторы. Любой, кто пишет фреймворк, должен был представить реальные доказательства своего утверждения.

underscore_d 17.01.2017 04:15
Я должен придерживаться чистого C++, потому что используемый мной фреймворк запрещает любое использование дженериков. There's certainly a rationale behind this decision? I'd be interested to hear it because off the top of my head I can't think of any reason to forbid templates completely.
Konrad Rudolph 26.08.2008 11:57

@KonradRudolph: Официальный ответ на это: Они не переносятся в другие операционные системы, особенно в том, как они поддерживаются компиляторами и редакторами ссылок.

Alexander Stolz 26.08.2008 12:05

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

DrPizza 26.08.2008 22:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
6
5 983
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Правила:

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

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

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

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

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

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

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

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

Я бы использовал std :: auto_ptr, чтобы показать, что судно-владелец передается (а не указатель RAW). Предположительно, вы уже сохраняете в интеллектуальном указателе, если ожидается единоличное владение, std :: auto_ptr идеально подходит.

Martin York 02.10.2008 19:22

ОП сказал, что он не может использовать дженерики, что, по-видимому, исключает любой тип интеллектуального указателя.

Sam Stokes 25.11.2008 22:10

Не будет ли дамп ядра приложения, если объект, на который указывает ссылка, удален по ошибке? Если бы это был указатель, мы могли бы проверить наличие null (при условии, что средство удаления установит его на null).

balki 10.10.2011 12:45

@balki Может; это может и не быть; это может вызвать дождь из тостеров с неба: это UB. Но Сандер сказал, что ссылки используются только в том случае, если есть гарантия, что они не станут свисающими, так что это проблема качества кода. И что еще более важно, указатели ничем не лучше: удаление объекта другим объектом не устанавливает копию указателя на nullptr наблюдателем, поэтому его нельзя проверить на достоверность больше, чем можно по ссылке (читайте: nullptrness - это свойство адреса, а не данных по этому адресу) ... если каждый наблюдатель ptr не зарегистрирован ссылкой с владельцем для последующего обновления или чего-то запутанного

underscore_d 17.01.2017 04:24

В общем случае (управление ресурсами, когда ресурс не обязательно является памятью) вам необходимо знать Шаблон 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 вам нужно все «новое», и трудно избавиться от этой привычки, особенно когда два языка выглядят очень похожими, но на самом деле совершенно разными. Для настоящего удовольствия попробуйте работать с обоими одновременно!

Chris Huang-Leaver 02.10.2008 18:33

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

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

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

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

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

Rudy Velthuis 31.07.2016 05:15

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