DO's и Donts при использовании указателей

Существуют различные требования для профилирования. Оснащен код хорошо, или необходимо ли представить оптимизированный код (или даже уже скомпилированный код)? Вы должны линию за линией представить информацию? Который ОС Вы выполняете? Необходимо ли представить совместно использованные библиотеки также? Что относительно трассировки в системные вызовы?

Лично, я использую oprofile для всего, что я делаю, но это не могло бы быть лучшим выбором в каждом случае. Vtune и Shark оба превосходны также.

7
задан 2 revs 12 November 2009 в 13:21
поделиться

10 ответов

C ++ specific

  • Избегайте ручного управления памятью , вместо этого используйте контейнеры RAII, такие как std :: auto_ptr , boost :: scoped_ptr , boost :: shared_ptr и эквивалентные массивы-контейнеры. Еще проще, часто std :: vector работает нормально, и это не так ' не требуют использования указателя вообще. Наконец, вместо передачи указателей на большие или изменяемые структуры данных вы можете передавать ссылки. Указатели могут представлять массивы, тогда как ссылки позволяют избежать этой двусмысленности.
  • Индексирующие массивы являются достойной заменой большей части арифметики указателей. Обычно это не медленнее, чем арифметика с указателями, которую часто легче ошибиться, а ее труднее читать и поддерживать. Как правило, не оптимизируйте микрооптимизацию за счет удобочитаемости.
  • Вызовите правильную процедуру освобождения: delete [] предназначена для массивов, выделенных через new ... [] только, delete только для указателей на отдельные объекты и free (...) только для памяти, выделенной через C api (например, malloc (..) ). Их нельзя путать; Подпрограммы освобождения C ++ включают вызовы деструкторов и, следовательно, должны вызываться правильно.
  • Явно инициализируйте и устанавливайте бессмысленные указатели на NULL . Случайное разыменование null легче отладить, чем неправильный доступ к памяти. Можно освободить указатель NULL , поэтому вам не нужно загромождать деструктор проверками, чтобы избежать этого. Если вы удаляете объект преждевременно, вы должны установить его указатель на NULL , чтобы избежать двойного удаления того же указателя и случайного разыменования висячего указателя.
  • Если вы ' повторно используют наследование C ++ и переопределяют деструктор, читайте в виртуальных деструкторах; они необходимы для правильности (короче, базовый класс должен явно пометить деструктор как виртуальный).
  • Знайте, кто «владеет» указателем , если вам нужно вручную управлять памятью. Только владелец должен освободить объект или массив, на который указывает указатель, и никакой другой объект не может использовать объект после того, как владелец удалит указатель на него. boost :: shared_ptr - это беспроблемный контейнер с довольно низкими накладными расходами, который часто подходит, когда вам нужно поделиться указателем.
18
ответ дан 6 December 2019 в 05:08
поделиться
  1. Всегда проверяйте, что указатели инициализированы.
  2. Всегда знайте длину выделенной области памяти
  3. Всегда проверяйте значение NULL при работе с указателем
  4. Всегда удаляйте указатели после вы используете их
  5. Никогда не перезаписывайте память за пределами указателя
  6. Никогда не доверяйте указателям достоверности, предоставленным вашим методам
  7. Никогда не помещайте вводимые пользователем данные в указатель (например, получает)
  8. Никогда не смешивайте malloc / бесплатно с помощью new / delete
  9. Никогда не выделяйте указатели на объекты класса с помощью malloc
  10. Никогда не освобождайте указатели объектов класса с помощью free

И последнее, но не менее важное

Никогда не используйте указатели, если вам не нужно ... Существуют (константные) ссылки, чтобы избежать создания копирования объектов, передаваемых функциям и контейнерам STL и строкам для других требований к хранилищу, и использовать smart (boost ::

12
ответ дан 6 December 2019 в 05:08
поделиться

В C

  • Не указывайте на память, которой вы не "владеете".
  • Не разыменовывайте NULL-указатели.
  • Освободите ресурсы, когда вам не нужно их.
  • Не теряйте из виду свои указатели (остерегайтесь сбоев повторной синхронизации).
  • Не злоупотребляйте void * .
  • Не смешивайте типы указателей: a char * - это не то же самое, что double ** .
  • Проверяйте возвращаемое значение функций, возвращающих указатели.
3
ответ дан 6 December 2019 в 05:08
поделиться

Записать стандартный код. Это должно позаботиться о платформе. И много других вопросов. И используйте const . Это решит больше проблем.

2
ответ дан 6 December 2019 в 05:08
поделиться

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

1
ответ дан 6 December 2019 в 05:08
поделиться

ПРИМЕЧАНИЕ. Ответ для C ->

Ниже приведены общие причины этого нарушения сегментации или ошибки сегментации:

Неправильная строка управления форматом в операторах printf или scanf: Убедитесь, что строка управления форматом имеет такое же количество спецификаторов преобразования (% 's), как printf или scanf имеет аргументы для печати или чтения, соответственно, и что спецификаторы соответствуют типу переменной, которая будет напечатана или прочитана. Это также относится к fprintf и fscanf.

Забыть использовать "&" в аргументах scanf: Функция scanf принимает в качестве аргументов строку управления форматом и адреса переменных, в которые она будет помещать считываемые данные. Оператор «&» (адрес) используется для указания адреса переменной. Часто забывают использовать "&" с каждой переменной в вызове scanf. Отсутствие символа «&» может вызвать нарушение сегментации.

Доступ за пределами массива: Убедитесь, что вы не нарушили границы любого используемого массива; то есть вы не присвоили массиву индекс со значением, меньшим, чем индекс его самого низкого элемента, или большим, чем индекс его самого высокого элемента.

Ошибка инициализации указателя перед доступом к нему: Переменной-указателю должен быть назначен действительный адрес (т. Е. Она должна отображаться слева от присваивания) до того, как к ней будет осуществлен доступ (т. Е. С правой стороны от присваивания). Убедитесь, что вы инициализировали все указатели, указывающие на допустимую область памяти. Правильная инициализация указателя может быть выполнена несколькими способами. Примеры приведены ниже.

Неправильное использование операторов «&» (адрес) и «» (разыменование): Убедитесь, что вы понимаете, как работают эти операторы. Знайте, когда их следует применять, а когда - нет. Как упоминалось выше, часто забывают использовать "&" с каждой переменной в вызове scanf. Помните, что scanf требует адреса переменных, которые он читает. В частности, знайте, когда «&» и «» абсолютно необходимы, а когда их лучше избегать.

Устранение неполадок:

Проверяйте ВСЕ места в вашей программе, где используются указатели, индексы массива или оператор адреса (&) и оператор разыменования (*). Каждый из них может стать причиной нарушения сегментации. Убедитесь, что вы понимаете использование указателей и связанных операторов. Если программа использует много указателей и имеет много вхождений & и *, добавьте несколько операторов printf, чтобы точно определить место, в котором программа вызывает ошибку, и исследовать указатели и переменные, задействованные в этом операторе.

Помните, что операторы printf для целей отладки должны иметь символ новой строки (\ n) в конце их строк управления форматом, чтобы принудительно очистить буфер печати.

1
ответ дан 6 December 2019 в 05:08
поделиться

Некоторое время назад я присоединился к проекту, в котором несколько хороших разработчиков использовали только голые указатели. Несмотря на то, что они обладают отличными навыками, их программа (работающая в Windows / Linux / HP-UX) время от времени вызывала сбои и утечки памяти.

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

1
ответ дан 6 December 2019 в 05:08
поделиться

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

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

0
ответ дан 6 December 2019 в 05:08
поделиться

Не пропустите проверку границ.

0
ответ дан 6 December 2019 в 05:08
поделиться

Не совсем ответ на вопрос «Где предпочтительнее использовать char *. над массивом символов? " вопрос, но кое-что, что недавно укусило кого-то, кого я просматривал, было «sizeof».

Подумайте вот о чем:

char *a = new char[3];
char b[3];

Во многих местах вы используете «a» и «b» Проблемы начинаются, когда вы делаете что-то вроде:

strncpy(b, some_string, sizeof(b));    
strncpy(a, some_string, sizeof(a));

Думаю, мораль этой истории такова: будьте осторожны с sizeof (). Вероятно, лучше поддерживать постоянный размер.

0
ответ дан 6 December 2019 в 05:08
поделиться