Подтвердить что ты не робот

С++: когда использовать указатели?

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

  • время жизни объекта управления;
  • не может использовать ссылки (например, вы хотите сохранить что-то не скопированное в вектор);
  • вы должны передать указатель на какую-либо третью функцию;
  • возможно, некоторые причины оптимизации, но я не уверен.

Ответ 3

Мне непонятно, если ваш вопрос - это ptr-to-obj vs stack-based-obj или ptr-to-obj vs reference-to-obj. Существуют также приложения, которые не попадают ни в одну категорию.

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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


void f() {
   string value;        // NOT string * value
   // use vvalue
}

Ответ 6

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

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

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

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

  • Для вашего объекта вам нужна сложная логика управления жизненным циклом.

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

Ответ 7

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

Ответ 8

Обычно используют указатели/ссылки на объекты, когда:

  • передача их другим методам

  • создание большого массива (я не уверен, что такое нормальный размер стека)

Используйте стек, если:

  • Вы создаете объект, который живет и умирает в рамках метода

  • Объект - это размер регистра процессора или меньше

Ответ 9

Я действительно использую указатели в этой ситуации:

class Foo
{
    Bar* bar;

    Foo(Bar& bar) : bar(&bar) { }

    Bar& Bar() const { return *bar; }
};

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

Dave

Ответ 10

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

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

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

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

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

Ответ 11

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

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

Ответ 12

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

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

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

Ответ 13

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

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

Ответ 14

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

Говоря о Qt конкретно, Qt помогает программисту, обрабатывая много управления памятью объектов кучи. Для объектов, полученных из QObject (почти все классы с префиксом "Q" ), конструкторы берут необязательный параметр parent. Затем родительу принадлежит этот объект, и когда родитель удален, все принадлежащие ему объекты также удаляются. По сути, ответственность за уничтожение детей передается родительскому объекту. При использовании этого механизма дочерний элемент QObject должен быть создан в куче.

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