2010-11-26 3 views
8

Я могу использовать объект в качестве указателя на него или его ссылку. Я понимаю, что разница заключается в том, что указатели должны быть удалены вручную, а ссылки остаются до тех пор, пока они не выйдут из области видимости.Объекты C++: Когда я должен использовать указатель или ссылку

Когда следует использовать каждый из них? Какова практическая разница?

Ни один из этих вопросов, ответил на мои сомнения:

+0

вам не нужно удалить сам указатель, а также ссылки автоматически не удалить объект ссылки. Вы уверены, что не путаете ссылки и ценности/объекты? – DaVinci 2010-11-26 19:29:48

+0

Я очень уверен в различии между разницей между значением/ссылкой. Моя проблема заключается в том, когда объявлять объект как указатель на него и передавать указатель вдоль или объявлять как значение и передавать его ссылку. – rafaelxy 2010-11-26 19:32:01

ответ

17

Ссылка в основном указатель с ограничениями (должен быть привязан к созданию, не может быть отскок/нуль). Если для вашего кода имеет смысл использовать эти ограничения, то использование ссылки вместо указателя позволяет компилятору предупредить вас о случайном нарушении их.

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

0

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

+0

Ну, ваш ответ помогает, но не решает все. Я все еще сомневаюсь, когда использовать ссылку на значение объекта или использовать указатель на него. – rafaelxy 2010-11-26 19:30:04

3

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

  • Указатель может быть переназначен в новое состояние . Ссылка не может. Это желательно в некоторых ситуациях.
  • Указатель помогает передать семантику владельца судна. Это особенно полезно в многопоточной среде, если состояние параметра используется для выполнения в отдельного потока, и вы обычно не проводите опрос до выхода потока. Теперь поток может удалить его.
2

Erm ... нетолько. Это IDENTIFIER имеет область действия. Когда вы создаете объект с использованием new, но область его идентификатора заканчивается, вы можете потерять память (или нет - зависит от того, чего вы хотите достичь) - объект находится в памяти, но у вас нет средств для его ссылки больше.

Разница заключается в том, что указатель является адресом в памяти, поэтому если у вас есть, скажем, этот код:

int * a = new int; 

a является указателем. Вы можете распечатать его - и вы получите что-то вроде «0x0023F1» - это просто: адрес. Он не имеет значения (хотя некоторое значение сохраняется в памяти по этому адресу).

int b = 10; 

b является переменной со значением 10. Если вы печатаете, вы получите 10.

Теперь, если вы хотите a, чтобы указать на b 'адрес s, вы можете сделать:

a = &b; //a points to b's address 

или если вы хотите адрес, на который указывает a иметь b' s значение:

*a = b; //value of b is assigned to the address pointed by a 

Пожалуйста, скомпилируйте этот образец и прокомментируйте/раскомментируйте строки 13 и 14, чтобы увидеть разницу (обратите внимание, где указаны идентификаторы и WHAT VALUE). Я надеюсь, что результат будет понятным.

#include <iostream> 

using namespace std; 

int main() 
{ 
    int * a = new int; 
    int b = 10; 
    cout << "address of a: " << a << endl; 
    cout << "address of b: " << &b << endl; 
    cout << "value of a: " << *a << endl; 
    cout << "value of b: " << b << endl; 
    a = &b; //comment/uncomment 
    //*a = b; //comment/uncomment 
    cout << "address of a: " << a << endl; 
    cout << "address of b: " << &b << endl; 
    cout << "value of a: " << *a << endl; 
    cout << "value of b: " << b << endl; 
} 
2

Давайте ответим на последний вопрос первым. Тогда первый вопрос будет иметь больше смысла.

В: «В чем практическая разница [между указателем и ссылкой]?»

A: Ссылка является лишь локальным псевдонимом для другой переменной. Если вы передадите параметр по ссылке, то этот параметр будет точно такой же переменной, как тот, который был указан в вызывающем операторе. Однако внутри обычно нет разницы между указателем и ссылкой. Ссылки предоставляют «синтаксический сахар», позволяя вам уменьшить количество ввода, которое вы должны делать, когда все, что вам действительно нужно, - это доступ к одному экземпляру данной переменной.

В: «Когда следует использовать каждую из них?»

A: Это будет вопрос личных предпочтений. Вот основное правило, за которым я следую. Если мне понадобится манипулировать переменной в другой области видимости, и эта переменная является либо внутренним типом, либо классом, который должен использоваться как внутренний тип (т.е. std :: string и т. Д.), Либо константа класса, затем я передаю ссылку. В противном случае, я пройду по указателю.

3

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

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

Еще короче: предпочитайте ссылки по указателям.

3

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

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

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

void UmbraEngine::addModule (UmbraModule * module) { 
    modules.push(module); 
    module->id = modules.size() - 1; 
} 

Получить один:

UmbraModule * UmbraEngine::getModule (int id) { 
    for (UmbraModule **it=modules.begin(); it != modules.end(); it++) { 
     if ((*it)->id == id) return *it; 
    } 
} 

Теперь я могу добавить и получить модули не зная их идентификаторы:

int main() { 
    UmbraEngine e; 
    for (int i = 0; i < 10; i++) { 
     e.addModule(new UmbraModule()); 
    } 
    UmbraModule * m = e.getModule(5); //OK 
    cout << m << endl; //"0x127f10" or whatever 
    for (int j = 0; k < 10; j++) { 
     UmbraModule mm; //not a pointer 
     e.addModule(&mm); 
    } 
    m = e.getModule(15); 
    cout << m << endl; //{null} 
} 

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

Другой хороший, но очень простой пример заключается в следующем:

void getVal (int * a) { 
    *a = 10; 
} 
int main() { 
    int b; 
    getVal(&b); 
    return b; 
} 
8

«указатели Я должен удалить и ссылки они остаются до конца своей области видимости.»

Нет, это совершенно неправильно.

Объекты, выделенные new, должны быть удалены [*]. Объекты, которые не выделены new, не должны удаляться. Можно указать указатель на объект, который не был выделен new, и возможно иметь ссылку на объект, который был выделен new.

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

[*] с delete. Массив, выделенный с помощью new[], должен быть удален с помощью delete[]. Существуют доступные инструменты, которые могут помочь отслеживать выделенные ресурсы и делать эти вызовы для вас, называемые интеллектуальными указателями, поэтому довольно редко нужно явно делать вызов самостоятельно, а не просто организовывать его, но тем не менее он должно быть сделано.

0

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

Хотя указатели могут быть перенаправлены в другое место, ссылки как постоянные указатели не могут быть перенаправлены. Таким образом, ссылки не могут использоваться для перемещения массивов в функциях и т. Д.

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

Я также прочитал, что время обработки для ссылок меньше,

, как

INT & I = Ь;

i ++; занимает меньше времени, чем

int * j = b;

(* j) ++;

, но я еще должен подтвердить это. Если кто-то может пролить свет на это утверждение, это было бы здорово.

Комментарии приветствуются :)

Смежные вопросы