Когда подходящее время использовать *, & или const в C ++? - PullRequest
11 голосов
/ 13 октября 2010

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

Я думаю, что первый прост, это то, что x является копией введенного параметра, поэтому в стеке создается другая переменная.Что касается остальных, я не знаю.

void doSomething1(int x){
    //code
}
void doSomething2(int *x){
    //code
}

void doSomething3(int &x){
    //code
}
void doSomething3(int const &x){
    //code
}

Я также вижу подобные вещи, когда объявляются переменные.Я не понимаю различий между ними.Я знаю, что первый поместит 100 в переменную y в стеке.Он не будет создавать новый адрес или что-либо еще.

//example 1
int y = 100;

//example 2
int *y = 100;

//Example 3: epic confusion!
int *y = &z;

Вопрос 1: Как я могу использовать эти методы?Когда это наиболее уместно?

Вопрос 2: Когда я объявляю переменные таким образом?

Примеры были бы хорошими.

PS Это одна из главных причин, почему я нене изучаю C ++, так как у Java просто есть сборщик мусора.Но теперь я должен войти в C ++.

Ответы [ 7 ]

10 голосов
/ 13 октября 2010
//example 1
int y = 100;

//example 2
int *y = 100;

//Example 3: epic confusion!
int *y = &z;

Я думаю, что проблема для большинства студентов в том, что в C ++ оба значения & и * имеют разные значения, в зависимости от контекста, в котором они используются.
Если либоиз них появляется после типа в объявлении объекта (T* или T&), они являются модификаторами типа и изменяютсятип от простого T до ссылка на T (T&) или указатель на T (T*) .
Если они появляются перед объектом (&obj или *obj), они одинарныепрефиксные операторы , вызываемые на объекте.Префикс & возвращает адрес объекта , для которого он вызывается, * разыменования указатель, итератор и т. Д., получая значение, на которое оно ссылается.

Это не помогает избежать путаницы в том, что модификаторы типа применяются к объявленному объекту, а не к типу.То есть T* a, b; определяет T* с именем a и простой T с именем b, поэтому многие люди предпочитают вместо этого писать T *a, b; (обратите внимание на расположение модифицирующего тип *рядом с определяемым объектом, а не с измененным типом).

Также бесполезно то, что термин «ссылка» перегружен.С одной стороны, это означает синтаксическую конструкцию, как в T&.Но есть также более широкое значение «ссылки», являющейся чем-то, что относится к чему-то другому.В этом смысле и указатель T*, и ссылка (другое значение T&) являются ссылками в том смысле, что они ссылаются на некоторый объект.Это вступает в игру, когда кто-то говорит, что «указатель ссылается на некоторый объект» или что указатель «разыменован».

Так что в ваших конкретных случаях # 1 определяет простой int, # 2 определяет указатель на int и инициализирует его с адресом 100 (все живые существа, вероятно, лучше оставить нетронутыми)и # 3 определяет другой указатель и инициализирует его адресом объекта z (также обязательно int).


A о том, как передавать объекты в функции в C ++, здесь - мой старый ответ на этот вопрос.

4 голосов
/ 13 октября 2010

от Скотта Майерса - более эффективный C ++ -> 1

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

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

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

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

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

2 голосов
/ 13 октября 2010

Прочитайте книгу С.Липпмана «C ++ Premier» или любую другую хорошую книгу по C ++. Что касается передачи параметров, обычно, когда копирование дешевое, мы передаем по значению. Для обязательных параметров out мы используем ссылки, для необязательных параметров out - указатели, для входных параметров, где копирование обходится дорого, мы передаем по const ссылкам

1 голос
/ 13 октября 2010
void doSomething1(int x){
//code
}
void doSomething2(int *x){
//code
}

void doSomething3(int &x){
//code
}

И я действительно запутался между ними?

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

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

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

Ваша путаница может быть связана с тем, что оператор '&' имеет два значения.Тот, с кем вы, похоже, знакомы, это «оператор ссылки».Он также используется как «оператор адреса».В приведенном вами примере вы берете адрес z.

Хорошей книгой, в которой подробно описывается все это, является «Ускоренный C ++» Эндрю Кенинга.

1 голос
/ 13 октября 2010

void doSomething1 (int x) {// code} Этот параметр передает переменную по значению, что бы ни происходило внутри функции, исходная переменная не изменяется

void doSomething2 (int * x) {// code} Здесь вы передаете переменную типа указатель на целое число.Так что при доступе к номеру вы должны использовать * x для значения или x для адреса

void doSomething3 (int & x) {// code} Здесь, как и в первом случае, но что бы ни происходило внутри функции,оригинальная переменная также будет изменена

int y = 100;нормальное целое число

// пример 2 int * y = 100;указатель на адрес 100

// Пример 3: эпическая путаница!int * y = & z;указатель на адрес z

1 голос
/ 13 октября 2010

Это действительно сложная тема.Пожалуйста, прочитайте здесь: http://www.goingware.com/tips/parameters/. Также Скотт Мейерс «Эффективный C ++» - лучшая книга по таким вещам.

0 голосов
/ 13 октября 2010

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

И, к сведению, знание указателей делает вас значительно болееценный на рабочем месте.(слишком часто программисты на C ++ - это «мистики» офиса, знающие, как эти магические коробки под партами обрабатывают код / ​​полусарказм)

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