Да, может. Единственный способ, которым мы могли бы сказать «это невозможно», - это если в стандарте было требование (явное или подразумеваемое), что ссылки должны быть такими же медленными или медленными, как эквивалентные указатели во всех случаях. Такого требования нет, поскольку стандарт не касается такого рода деталей производительности.
Например, при низких уровнях оптимизации было бы разумно для этого:
int n = 0;
int *np = &n;
for (int i = 0; i < 10000000; ++i) {
*np += i;
}
std::cout << n;
быть немного медленнее, чем это:
int n = 0;
int &nr = n;
for (int i = 0; i < 10000000; ++i) {
nr += i;
}
std::cout << n;
просто потому, что в первом случае компилятору немного проще обнаружить, что он может полностью избежать косвенного обращения - nr
явно является псевдонимом для n
везде, где он находится в области видимости, тогда как *np
именно так и происходит оставаться псевдонимом для n
, потому что мы никогда не присваиваем np
после его инициализации. Результатом с низкой оптимизацией может быть больше косвенности в случае указателя и менее эффективный цикл.
Взгляните на код, который выдает ваш компилятор, хотя - gcc без оптимизации выдает для меня один и тот же код, похоже, что он обнаружил псевдоним в обоих случаях и использует регистр для общего значения и слот стека для i
.
Конечно, вы ожидаете, что хороший оптимизирующий компилятор "поймет" псевдонимы в обоих случаях и выдаст код, который хранит n
в регистре и касается только этого регистра (но не памяти) в цикле.