Причины проектирования поведения эталонных членов классов, передаваемых по константной ссылке

Предположим, чтобы иметь код

#include <iostream>

struct A{
  int y;
  int& x;
  A():y(0),x(y){}
};



void f(int& x){
  x++;
}

void g(const A& a){
  f(a.x);
  //f(a.y);
}


int main(){
  A a;
  g(a);
  std::cout<<a.y<<std::endl;

}

внутри g() вызов f() для y недопустим, поскольку a передается с модификатором const, однако значение y можно изменить внутри g(), вызывая f для x;

С помощью указателей похожие вещи можно получить очень похожим образом.

struct B{
  int* x;  
}

а также

g(const B&){
   *x++;
}

позволено. Это совершенно ясно: у нас есть константный указатель на неконстантный int. Но в предыдущем ссылочном примере, если ссылки являются объектом, почему в этом случае они ведут себя как указатели? Каковы политики дизайна под этим поведением?

3 ответа

Решение

Фактический язык в стандарте

C++ 11

8.3.2 Ссылки [dcl.ref]

1 - [...] [Примечание: ссылка может рассматриваться как имя объекта. —Конечная записка]

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

Мы также видим

6 - Если typedef, параметр шаблона типа или спецификатор decltype обозначает тип TR, который является ссылкой на тип T, попытка создать тип "lvalue ссылка на cv TR" создает тип "lvalue ссылка на Т ” [...]

Поскольку доступ члена к объекту cv создает значение cv lvalue, то же самое применяется, и квалификация cv прекращается.

если ссылки являются объектом

хотя ссылки не являются объектами - это ссылки на объекты.

Вы правы в том, что создание ссылки const само по себе не очень полезно: поскольку они не подлежат повторной настройке, их нельзя изменять как указатели в любом случае.

Фактически, было бы более полезно думать о ссылке как о константном указателе (не указателе на константу!) Со специальным синтаксисом.

Обратите внимание, что если вы хотите косвенное обращение, которое распространяет константность от рефери к референту (то есть, чтобы предотвратить f(a.x) позвоните сюда), вы можете написать умную вещь в стиле указателя, чтобы сделать это.


Конкретный пример

struct A
{
    int x;
    int *p;
    int &r;

    A() : x(0), p(&x), r(x) {}
};

Сейчас в A a:

  • a.x изменчивый int
  • a.p является изменяемым указателем (таким образом, мы можем переустановить его) на изменяемое целое (мы можем изменить значение целого числа, на которое он указывает)
  • а также a.r ссылка на изменяемый int
    • обратите внимание, что, поскольку мы не можем изменить (переустановить) ссылки в любом случае, это не означает, что сама ссылка является постоянной или изменяемой

... но в const A b:

  • b.x постоянное целое число
  • b.p постоянный указатель (поэтому мы не можем переустановить его) на изменяемый int
  • b.r ссылка на изменяемый int
    • обратите внимание, как константность применяется к элементу A (указателю или ссылке) и не распространяется на референт.

В C++ ссылки обычно реализуются указателями. (Я думаю, что sizeof ссылка и указатель одинаковы).

Действительно, я обычно считаю ссылки указателями, но с другим синтаксисом.

Другие вопросы по тегам