Я привык заниматься программированием на Java, когда при программировании никогда не приходится думать об указателях. Однако сейчас я пишу программу на C++. Когда я должен использовать указатели, а когда нет, при создании классов, которые имеют члены других классов? Например, когда я хочу это сделать:
class Foo {
Bar b;
}
В отличие от этого:
class Foo {
Bar* b;
}




Оба подходят в разных условиях. Например, если вы знаете, как построить b, когда создается объект класса Foo, первое - в порядке. Но если вы этого не сделаете, единственный выбор - использовать второй.
Начните с избегания указателей.
Используйте их, когда:
Bar фактически управляется какой-то другой частью вашей программы, тогда как класс Foo просто должен иметь к нему доступ.Bar (т.е. вы хотите создать его после, создавая Foo).Bar может вообще не существовать; вы бы также использовали null в Java. Однако проверьте также boost :: optional.Bar на самом деле является базовым классом, и вам нужно, чтобы экземпляр был полиморфным.В любом из этих случаев (*) начните с использования интеллектуального указателя, такого как boost :: shared_ptr. В противном случае вы, скорее всего, рано или поздно забудете освободить память. Когда вы поймете, что делаете, в каждом конкретном случае подумайте, какой тип указателя лучше всего подходит.
(*) в любом случае - кроме, наверное, пункта о виджетах GUI; в этом случае ваш инструментарий, скорее всего, также будет управлять ресурсами за вас.
может я один. но я думаю, что особенно новички должны (конечно, не в реальных проектах) сначала попробовать поработать с необработанными указателями. Думаю, это похоже на вопрос «IDE / no IDE». они должны знать, что умные указатели Зачем полезны и каких ловушек они избегают
перед тем, как взять и использовать их, чтобы волшебным образом избежать некоторых проблем, о которых им рассказывали другие.
@litb: Я согласен с вашей точкой зрения. Думаю, ответ будет немного другим, если вы спросите о лучших практиках для реальных проектов (на этот вопрос я отвечал) или научитесь понимать фундаментальные вещи. OTOH, я подумал, что он уже знал, как работать с необработанными указателями в базовом случае.
Начальная точка должна быть boost :: scoped_ptr, используйте shared_ptr только тогда, когда вам нужна эта функциональность.
@ Патрик: Верно. «Поскольку он не копируемый, он безопаснее shared_ptr или std :: auto_ptr для указателей, которые не следует копировать». Однако это не сработает в ситуации, описанной во втором пункте.
Если вы программируете на Qt, используйте QPointer <T> как умный указатель.
В первом примере память для объекта Bar будет выделена автоматически при создании объекта Foo. Во втором случае вам нужно выделить память самостоятельно. Итак, вы должны вызвать:
Foo *foo = new Foo();
foo->b = new Bar();
Это может быть желательно, если объект Bar большой и вы не хотите связывать его с объектом Foo. Также желательно, чтобы создание объекта Bar не зависело от создания объекта Foo. В этом случае объект b "вводится" в foo:
Foo *foo = new Foo();
foo->b = b_ptr;
где b_ptr создается где-то еще, а указатель передается на foo.
Для небольших объектов это опасно, так как вы можете забыть выделить память.
new возвращает указатель, а не значение. Вы имеете в виду Foo foo; или Foo foo = Foo (); вместо?
class Foo {
Bar b;
}
b - это содержал в Foo. Если у объекта Foo заканчивается время жизни, b автоматически завершает время жизни. Это то, что моделирует композиция. b выше обозначает сам объект, а не просто указатель на него, как в Java. Поэтому, если b выходит за пределы области видимости, срок жизни объекта истекает.
class Foo {
Bar * b;
}
Здесь объект b указывает на использован или на который ссылается объект Foo. Если время жизни объекта Foo заканчивается, объект b, на который указывает, может продолжать жить, в зависимости от обстоятельств. Это можно использовать для моделирования агрегирования и общих отношений. Например, этот объект может использоваться совместно с другими объектами Foo.
Указатели примерно соответствуют ссылкам в Java. Они также могут ни на что не указывать. Если указатель ни на что не указывает, это нулевой указатель.
Ссылки похожи на указатели. Ссылки в C++ должны быть инициализированы и могут указывать только на один (действительный) объект, для которого была инициализирована ссылка. Поэтому ссылка не может содержать значение, которое могло бы означать «ничего», как null в Java.
Это может быть слишком поздно, но в первом абзаце не следует ли вам говорить: «Если у объекта Foo заканчивается время жизни, b автоматически завершает время жизни». вместо Bar вместо Foo.
Вам нужно немного заняться программированием на ассемблере и хорошо понимать структуру памяти. C - это просто кроссплатформенная сборка, в отличие от Java или других языков. Чтобы использовать его правильно, нужно понимать детали низкого уровня.
Все сделанные комментарии действительны, но для таких людей, как вы, которые перескакивают с языков высокого уровня на C, такой опыт будет более чем полезен. При правильном понимании вы бы больше не задавали подобных вопросов.
Обратите внимание, что вопрос касался C++, а не C.
Но новички не знают разницы между C++ и C. Это был хороший совет.
... или в случае, если вы пишете инструментарий (что часто бывает в моем случае). У меня никогда не было проблем с указателями, которые могли бы решить интеллектуальные указатели, поэтому я бы не стал говорить «ИСПОЛЬЗУЙТЕ ИХ!» но «в большинстве случаев их проще всего использовать».