C ++: разница между синтаксисами указателей - PullRequest
1 голос
/ 30 января 2012

Хорошо, так что в последнее время я глубоко вникаю в C ++, и у меня все получается. Указатели наконец начинают понимать, когда мне следует их использовать, как правильно их реализовать и т. Д.

Тем не менее, был один маленький вопрос о фундаментальном использовании указателей, на который у меня все еще был ответ, на который мне нужно было ответить. Я прыгну прямо на код:

Со следующим классом A и функцией foo(A* bar) ...

class A
{}

void foo(A* bar)
{}

... в чем разница между следующими вызовами foo?

A* a;
A b;

foo(a);
foo(&b);

Они оба прекрасно компилируются, и, насколько я помню, у меня не было с ними проблем.

Я думаю, что A b; создается прямо здесь, тогда как A* a; необходимо создать с помощью new (так как он фактически не создал объект, он просто содержит 4-байтовую длинную ссылку на потенциал A объект).

Я мог бы, если я правильно об этом думаю, сделать a = b; ( РЕДАКТИРОВАТЬ сделать это a = &b) и затем успешно передать a в foo. Но если я не сделаю a = &b и foo попытается прочитать (несуществующий) объект, на который указывает a, это вызовет ошибки времени выполнения.

Кроме того, если вышеприведенное верно, то предполагается, что я могу успешно позвонить foo(&b); просто отлично.

Я прав?

Спасибо!

Ответы [ 4 ]

5 голосов
/ 30 января 2012

Да, ваше понимание верно.

 foo(&b);

передает адрес уже существующего объекта типа A в качестве параметра функции foo().

foo(a);

передает указатель на тип A в качестве параметра функции. Чтобы иметь возможность делать что-либо значимое, оно должно указывать на действительный A объект. Это может быть сделано двумя способами:

Выделение объекта в стеке:
Создайте объект типа A в стеке (локальное хранилище) и сделайте указатель a, указывающий на этот объект:

A* a;
A b;

a = &b;

Динамическое выделение памяти:

   A *a = new A;

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

delete a;

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

4 голосов
/ 30 января 2012

Вы не можете сделать a = b.

Это должно быть a = &b, чтобы установить a на адрес b.

Вы также правы в отношении управления памятью: b выделяется в стеке, тогда как a выделяет пространство только для указателя и оставляет создание фактического объекта для вас.

foo(&b) будет работатьфайл, в котором поведение foo(a) будет неопределенным до инициализации *a (например, через a = new A()).

3 голосов
/ 30 января 2012

В C ++ указатели являются первоклассными объектами. Указатель - это не просто невидимая ссылка, которой требуется связанный объект для идентификации. Так работают ссылки на Java / C # (или на большинство других языков), но указатель сам по себе является объектом.

Итак, A* a объявляет указатель. Это не указывает ни на что, и у него нет , чтобы указывать на что-либо. И если / когда он указывает на что-то, ему не нужно владеть этим чем-либо.

Так что вам не нужно делать a = new A(). Вы также можете сделать a = &b (чтобы a содержал адрес объекта b. Или он также может указывать на любой другой объект типа A. Указатель - это просто объект, который хранит адрес Это ключ к вашему пониманию, что вы отбрасываете понятие, что у него "есть объект", который "должен быть создан".

Это - это объект, который содержит адрес (или содержит специальное значение null), и если он содержит адрес, в этом случае может быть или не быть объект типа A адрес.

0 голосов
/ 30 января 2012

Вы в основном правы.Не следует полагать, что указатели имеют длину 4 байта (например, это может быть 8 в системах amd64).Кроме того, ваше назначение должно быть a = &b; (обратите внимание на добавление оператора адреса).Кроме этого, это звучит довольно разумно.

...