Я всегда думал, что ссылки функционально совпадают с указателями, они просто имеют более дружественный синтаксис и некоторые другие незначительные различия (ссылки не могут быть присвоены нулю, они не могут быть переназначены).
Но сегодня я увидел этот код и не понимаю, почему он правильный:
Есть простая структура, Color3B. Мы создаем один в стеке так:
Color3B color(255,0,0);
Есть еще один класс, одна из его переменных экземпляра имеет тип Color3B.
class Node{
private:
Color3B _color;
public:
void setColor(const Color3B& color){
_color = color;
}
};
Использование:
void someFunction(){
Color3B color(255,0,0);
_someNode->setColor(color);
}
Я думаю, что цвет разрушается, когда он выходит за рамки: когда завершается некоторая функция. Но setColor получает адрес памяти чего-либо, созданного в стеке, и сохраняет его. Но нет никаких проблем, когда я получаю доступ к _color узла, он всегда там и имеет правильное значение.
Что мне здесь не хватает?
_color = color;
принимает значение копии color
так что не важно, что color
в конце концов выходит за рамки.
У вас будут проблемы, если переменная-член _color
было сам ссылка.
void someFunction(){
Color3B color(255,0,0); // (1)
_someNode->setColor(color);// (2)
} // (5)void setColor(const Color3B& color){ // (2)(3)
_color = color; // (4)
}
Давайте посмотрим, что здесь происходит:
color
setColor
color
теперь ссылка (псевдоним) color
color
в _color
(назначение), потому что _color
не ссылкаcolor
уничтоженОшибка, которая, по вашему мнению, должна произойти, произойдет, если _color
была ссылка.
class Node{
private:
const Color3B& _color;
public:
void setColor(const Color3B& color){
_color = color;
}
};
Этот код выдаст ожидаемую ошибку. Теперь вы фактически сохраните адрес цвета в стеке в Node
и это будет уничтожено в конце someFunction()
, Однако вы этого не делаете. Ваш Node
имеет свой Color3B
объект, а не ссылка на него. Итак, код _color = color
на самом деле выполняет копию из цвета в someFunction()
к цвету в Node
объект. Теперь, даже если исходный цвет будет уничтожен, один в Node
Живет на.
Если вы написали setColor()
с указателем эквивалент вашего кода будет:
void setColor(const Color3B* color){
_color = *color;
}
Потому что ссылка — это не адрес переменной, а псевдоним. Так color
в приведенном выше коде (если это ссылка) представляет значение его, а не адрес. Чтобы получить адрес, вам нужно написать &color
,