C ++: когда использовать указатели? - PullRequest
16 голосов
/ 18 марта 2009

После прочтения некоторых уроков я пришел к выводу, что всегда следует использовать указатели на объекты. Но я также видел несколько исключений при чтении некоторых руководств по QT (http://zetcode.com/gui/qt4/painting/), где объект QPaint создается в стеке. Так что теперь я в замешательстве. Когда я должен использовать указатели?

Ответы [ 14 ]

42 голосов
/ 18 марта 2009

Если вы не знаете, когда следует использовать указатели, просто не используйте их.

Это станет очевидным, когда вам нужно их использовать, каждая ситуация различна. Нелегко подвести итог, когда они должны использоваться. Не заводите привычку «всегда использовать указатели на объекты», это, безусловно, плохой совет.

21 голосов
/ 18 марта 2009

Основные причины использования указателей:

  1. время жизни объекта управления;
  2. не может использовать ссылки (например, вы хотите хранить что-то не копируемое в векторе);
  3. вы должны передать указатель на какую-нибудь стороннюю функцию;
  4. Может быть, некоторые причины оптимизации, но я не уверен.
15 голосов
/ 18 марта 2009

Мне не ясно, является ли ваш вопрос ptr-to-obj против obj на основе стека или ptr-to-obj по сравнению со ссылкой на obj. Есть также применения, которые не попадают ни в одну из категорий.

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

Что касается ссылок, всегда старайтесь использовать ссылки, но есть вещи, которые вы можете делать только с ptrs, например (есть много вариантов использования):

  • обход элементов в массиве (например, переход по стандартному массиву [])
  • когда вызываемая функция выделяет что-то и возвращает это через ptr

Самое главное, что указатели (и ссылки, в отличие от автоматических / основанных на стеке и статических объектов) поддерживают полиморфизм. Указатель на базовый класс может фактически указывать на производный класс. Это фундаментально для поведения ОО, поддерживаемого в C ++.

10 голосов
/ 18 марта 2009

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

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

С другой стороны, если объекты являются локальными для функции, то лучше использовать их в стеке. Это позволяет компилятору вызывать деструктор, когда элемент управления покидает функцию.

4 голосов
/ 18 марта 2009

Обычно вы должны использовать указатели в следующих сценариях:

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

  2. Вам нужна коллекция объектов, выделенная из стека, настолько большая, что это может вызвать переполнение стека.

  3. Вам нужна структура данных, которая может быстро переставлять объекты - например, связанный список, дерево и тому подобное.

  4. Вам нужна сложная логика управления временем жизни для вашего объекта.

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

4 голосов
/ 18 марта 2009

Какие уроки будут? На самом деле, правило состоит в том, что вы должны использовать указатели только тогда, когда это абсолютно необходимо, что довольно редко. Вам нужно прочитать хорошую книгу по C ++, например, Ускоренный C ++ от Koenig & Moo.

Редактировать: Чтобы прояснить немного - два случая, когда вы бы не использовали указатель (здесь в качестве примера используется строка - то же самое будет идти для любого другого типа):

class Person {
   public:
      string name;       // NOT string * name;
   ...
};


void f() {
   string value;        // NOT string * value
   // use vvalue
}
2 голосов
/ 18 марта 2009

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

1 голос
/ 03 марта 2011

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

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

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

1 голос
/ 28 марта 2009

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

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

1 голос
/ 28 марта 2009

использование указателей связано с двумя ортогональными вещами:

  1. Динамическое распределение . В общем случае вы должны выделять динамически, когда объект должен жить дольше, чем область, в которой он создан. Такой объект является ресурсом, владельца которого нужно четко указать (чаще всего это своего рода умный указатель).

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

    • некоторые уже существующие интерфейсы требуют этого.
    • ассоциация, которая может быть нулевой, должна моделироваться.
    • Следует избегать копирования больших объектов, иначе копирование вообще невозможно, но ссылка не может быть использована (например, коллекции stl).

# 1 и # 2 могут встречаться в разных конфигурациях, например, вы можете представить себе динамически размещенный объект, доступ к которому осуществляется по указателю, но такой объект также может быть передан по ссылке на некоторую функцию. Вы также можете получить указатель на некоторый объект, который создается в стеке и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...