Неконстантные версии
Следует использовать указатели, когда:
1. Нужна опциональность (значение указателя может быть nullptr)
// Поиск элемента - может не найти
Node* findNode(Node* root, int value) {
if (!root) return nullptr; // Вариант "не найдено"
// ... поиск
}
2. Нужна динамическая память
int* array = new int[100];
// ...
delete[] array;
3. Нужна адресная арифметика
int arr[10];
int* ptr = arr;
ptr += 5; // Перемещение по массиву
4. Нужно перенаправление
int a = 1, b = 2;
int* current = &a;
// ... позже
current = &b; // Теперь указывает на b
Следует использовать ссылки, когда:
1. Обязательный параметр функции
void process(std::string& str) { // str обязательно должен существовать
// работаем со строкой
}
2. Перегрузка операторов
Vector& operator+=(const Vector& other) {
// ...
return *this; // Возвращаем ссылку на себя
}
3. Range-based for loops
for (auto& item : container) { // Изменяем элементы
item.process();
}
4. Алиасы для длинных типов
using Matrix = std::vector<std::vector<double>>;
void foo(Matrix& m) { // Проще, чем указатель
// ...
}
Константные версии
1. Константный указатель vs Указатель на константу
int x = 10, y = 20;
const int* ptr1 = &x; // Указатель на константу
// *ptr1 = 30; // ОШИБКА: нельзя менять значение
ptr1 = &y; // OK: можно менять указатель
int* const ptr2 = &x; // Константный указатель
*ptr2 = 30; // OK: можно менять значение
// ptr2 = &y; // ОШИБКА: нельзя менять указатель
const int* const ptr3 = &x; // И то, и другое
// *ptr3 = 30; // ОШИБКА
// ptr3 = &y; // ОШИБКА
2. Константная ссылка
const int& ref = x; // Ссылка на константу
// ref = 40; // ОШИБКА: нельзя менять
Готовое практическое правило
Существует готовое практическое правило: "Use references when you can, pointers when you must", т. е.:
Используйте ссылки, когда можете, указатели — когда должны!
Итоговая таблица
Все вышесказанное можно свести в таблицу:
|
Ситуация
|
Указатель |
Ссылка |
|
Может отсутствовать значение |
nullptr |
Не бывает |
|
Изменение цели |
Можно |
Нельзя |
|
Передача в функцию |
func(&var) |
func(var) |
|
Внутри функции |
if (ptr) *ptr = ... |
ref = ... |
|
Массивы |
ptr++, ptr[5] |
Только один элемент |
|
Синтаксис |
Явный (*, ->, &) |
Неявный (как переменная) |
Ссылка — это безопасный, не-NULL указатель, который нельзя перенаправить, с более чистым синтаксисом.
Указатель — более гибкий, но потенциально опасный инструмент, требующий осторожности.