Когда подходящее время для использования *, & или const в С++?

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

Я думаю, что первый из них прост, так что 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: Когда я объявляю переменные таким образом?

Примеры были бы замечательными.

P.S. это одна из основных причин, по которым я не изучил С++, поскольку Java просто имеет сбор мусора. Но теперь мне нужно попасть на С++.

Ответ 1

//example 1
int y = 100;

//example 2
int *y = 100;

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

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

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

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

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


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

Ответ 2

От Скотта Майерса - Более эффективный С++ → 1

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

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

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

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

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

Ответ 3

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

Ответ 4

Это действительно сложная тема. Читайте здесь: http://www.goingware.com/tips/parameters/. Также Скотт Мейерс "Эффективный С++" - это топ-книга о таких вещах.

Ответ 5

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

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

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

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

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

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

Ответ 6

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

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

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

Первый использует значение pass-by-value, и аргумент функции будет сохранять свое первоначальное значение после вызова.

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

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

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

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

Ответ 7

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

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