Что предпочтительней: ссылка или указатель?
С одной стороны, ссылки и указатели похожи: оба средства позволяют косвенно обратиться к другому объекту. Но различия между ними достаточно большие.
- Ссылка – это всего-лишь псевдоним (альтернативное имя). Обращаясь по ссылке мы обращаемся непосредственно к объекту, на который ссылка ссылается. Указатель – это указатель на объект. Т.е. совершенно другой объект, который содержит в себе данные об адресе объекта, на который он ссылается. Поэтому указатель занимает память, а ссылка нет.
- Ссылки безопасней указателей. Ссылка не может быть не инициализированной, как это, время от времени, бывает с указателями. Также, ссылка не может указывать на NULL, поэтому их использование не требует дополнительных проверок.
Некоторые программисты считают, что при передаче аргументов, в случае использования этих аргументов для записи, указатели предпочтительней:
void func1(int *a, int *b);
...
int a, b;
func1( &a, &b ); // Взятие адреса подсказывает, что func запишет
// какие-то данные в переменные a и b
void func2(int &a, int &b);
...
int a, b;
func2( a, b ); // В данном случае требуется взглянуть на сигнатуру
// func2, чтобы понять, для чего используются аргументы
Константные ссылки обладают возможностью продлевать жизнь переменным. К примеру вот такой код:
std::string getString();
...
const std::string &s = getString();
// используем s
совершенно корректен. Если бы ссылка не была константной, то мы получили бы ссылку разрушенный объект. Указатель также получился бы некорректным. Используя ссылку мы избежали конструирования лишнего объекта.
Их использование иногда позволяет улучшить интерфейс. К примеру стандартное использование ссылок:
template<typename T>
class vector {
public:
...
T & operator [](int i) {
return data[i];
}
const T & operator [](int i) const {
return data[i];
}
private:
T *data;
};
Таким образом мы получаем естественный интерфейс для значений элементам массива:
vector<int> v;
...
v[10] = 11;
Или вот такой интерфейс, позволяющий использовать одни и те же методы как левой, так и в правой части выражения:
class Person {
public:
std::string &firstName() {
return firstName_;
}
std::string &lastName() {
return lastName_;
}
int &age() {
return age_;
}
private:
std::string firstName_;
std::string lastName_;
int age;
};
...
Person person;
person.firstName() = "Vasya";
person.lastName() = "Pupkin";
person.age() = 45;
std::cout << person.firstName() << " " << person.lastName() << std::endl;