помилка: недійсна ініціалізація посилання non-const типу 'int &' із значення r типу 'int'


87

Неправильна форма:

int &z = 12;

Правильна форма:

int y;
int &r = y;

Питання :
чому перший код помилковий? Яке " значення " помилки в назві?


4
Не можна прив'язувати тимчасові посилання до непостійних посилань. int (12) в цьому випадку є тимчасовим.
Prasoon Saurav

@PrasoonSaurav Що ви маєте на увазі під тимчасовим 12? Відсутність понять тут (з мого боку :))
Aquarius_Girl

2
Зверніть увагу, що для цього обмеження немає суворої технічної причини. Це було б так само просто здійснити, щоб дозволити змінювані посилання на тимчасові. Заборона це - дизайнерське рішення С ++, оскільки така конструкція буде поганою конструкцією з набагато більшим ризиком випадкового зловживання, ніж справжня корисність. (Я лише одного разу виявив надуману потребу в такому.)
Керрек СБ

@KerrekSB найпоширенішою необхідністю посилання на об'єкт rvalue, мабуть, є(ostringstream() << "x=" << x).str()
curiousguy

@curiousguy: Так, це вміст посилання, яке я розмістив.
Kerrek SB

Відповіді:


132

C ++ 03 3.10 / 1 говорить: "Кожен вираз є або значенням l, або значенням r." Важливо пам’ятати, що lvalueness проти rvalueness - це властивість виразів, а не об’єктів.

Lvalues ​​називає об'єкти, які зберігаються за межами одного виразу. Так , наприклад, obj, *ptr, ptr[index]і ++xвсе lvalues.

Rvalues ​​- це тимчасові періоди, які випаровуються в кінці повного виразу, в якому вони живуть ("з крапкою з комою"). Так , наприклад, 1729, x + y, std::string("meow")і x++все rvalues.

Адреса оператора вимагає, щоб його "операнд був значенням". якщо ми могли б взяти адресу одного виразу, вираз є значенням, інакше це значенням r.

 &obj; //  valid
 &12;  //invalid

2
" якби ми могли взяти адресу одного виразу, вираз є значенням, інакше це значенням ". якби тільки С ++ був таким простим! (але нюанс тут насправді не актуальний) "Rvalues ​​are temporaries" тимчасовий що? об'єкти?
curiousguy

2
@curiousguyRvalues ​​- це тимчасові компанії, які зникають в кінці повного виразу, в якому вони живуть. Щоб просто відповісти, чому експрес int & = 12;недійсний, стандарт говорить, що рядковий літерал є значенням, інші літерали - значеннями r.
BruceAdi

@curiousguy: Так. Оцінки - це тимчасові об'єкти , але не всі значення - тимчасові об'єкти; деякі навіть не є предметами.
Nawaz

" Наприклад, 1729, x + y, std :: string (" мяу ") і x ++ - це всі значення r. ", Але std::string("meow")створює об'єкт типу std::stringі видає значення r, яке позначає цей об'єкт, 1729не має побічного ефекту і дає значення 1729 р. Як значення типу int.
curiousguy

1
@curiousguy: Твердження "Lvalues name objects that persist beyond a single expression."- це 100% правильне твердження. Навпаки, ваш приклад (const int &)1неправильний, оскільки це НЕ "названий" об'єкт.
Nawaz

53
int &z = 12;

Праворуч тимчасовий об'єкт типу intстворюється із цілісного літералу 12, але тимчасовий не може бути прив'язаний до посилання, що не є const. Звідси і помилка. Це те саме, що:

int &z = int(12); //still same error

Чому створюється тимчасовий? Оскільки посилання має посилатися на об'єкт у пам'яті, а для того, щоб об'єкт існував, його потрібно створити спочатку. Оскільки об'єкт не називається, це тимчасовий об'єкт. Він не має назви. З цього пояснення стало майже ясно, чому другий випадок добре.

Тимчасовий об'єкт може бути прив'язаний до посилання const, а це означає, що ви можете зробити це:

const int &z = 12; //ok

Посилання на C ++ 11 та Rvalue:

Для повноти я хотів би додати, що в C ++ 11 введено rvalue-reference, яке може прив'язуватися до тимчасового об'єкта. Отже, в C ++ 11 ви можете написати це:

int && z = 12; //C+11 only 

Зверніть увагу, що існує &&ціла кількість &. Також зауважте, що constце більше не потрібно, навіть якщо об’єкт, який zприв’язується, є тимчасовим об’єктом, створеним із цілісного літералу 12.

Оскільки C ++ 11 ввів rvalue-reference , int&відтепер він називається lvalue-reference .


10

12- константа часу компіляції, яку неможливо змінити на відміну від даних, на які посилається int&. Що ви можете зробити, це

const int& z = 12;

2
@curiousguy, будьте послідовними, ви сказали: "Ви повинні розуміти, що це правила C ++. Вони існують і не потребують жодних обґрунтувань" (не кажучи вже про перше видання). Як я можу інтерпретувати вашу скаргу на те, що ви не даєте того, що, на вашу думку, не потрібно?
Михайло Крелін - хакер

2
@ MichaelKrelin-hacker: Технічно ні, ви не можете (ніколи) прив'язувати посилання на значення (або компілювати часову константу), стандарт досить чітко визначає, що насправді відбувається: В іншому випадку створюється тимчасовий тип "cv1 T1" і ініціалізується з виразу ініціалізатора, використовуючи правила неідентифікаційної копії-ініціалізації (8.5). Потім посилання прив'язується до тимчасового. Тобто синтаксис дозволений, але семантика - це не прив'язка посилання на константу, а прив'язка його до тимчасового, яке створено неявно.
Девід Родрігес - dribeas

1
@curiousguy: Правила мови є частиною дизайну, і найчастіше існують обґрунтування, чому мова була розроблена так. У цьому конкретному випадку, як і в C, вам заборонено приймати адресу значення (воно не має такого), а також ви не можете прив'язати посилання. Тепер розглянемо функцію void f( vector<int> const & ), яка ідіоматично передає вектор, який не підлягає зміні. Зараз проблема полягає в тому, що f( vector<int>(5) )це буде неправильно, і користувачеві доведеться забезпечити інше перевантаження, void f( vector<int> v ) { f(v); }яке є тривіальним.
Девід Родрігес - дріба

1
... тепер, оскільки це було б боляче для користувачів мови, дизайнери вирішили, що компілятор виконає для вас еквівалентну операцію, у виклику f( vector<int>(5) )компілятор створює тимчасовий, а потім прив'язує посилання на цей тимчасовий, і так само якщо відбулося неявне перетворення 5безпосередньо. Це дозволяє компілятору генерувати єдиний підпис для функції і дозволяє реалізацію функції для одного користувача. Відтепер подібна поведінка визначається для решти використання постійних посилань для узгодженості.
Девід Родрігес - дріба

1
@ MichaelKrelin-hacker: посилання є псевдонімами об'єктів, а значення не є об'єктом. Залежно від контексту, посилання можуть бути лише псевдонімами, компілятор видаляє посилання і просто використовує ідентифікатор, щоб означати будь-який початковий об'єкт ( T const & r = *ptr;будь-яке подальше використання rу функції може бути замінено *ptrі rне повинно існувати під час виконання) або, можливо, його доведеться реалізувати, зберігаючи адресу об'єкта, який він псевдонім (розгляньте можливість збереження посилання як члена об'єкта) - який реалізований як вказівник на автоматичні посилання.
Девід Родрігес - dribeas

4

Прив'язка посилань, що не є const та const, відповідає різним правилам

Ось правила мови С ++:

  • вираз, що складається з буквального числа ( 12), є "значенням"
  • не дозволяється створювати посилання non-const зі значенням r: int &ri = 12;неправильно сформовано
  • дозволяється створювати посилання на const зі значенням r: у цьому випадку компілятор створює безіменний об’єкт; цей об'єкт зберігатиметься доти, доки існує сама посилання.

Ви повинні розуміти, що це правила на C ++. Вони просто є.

Легко винайти іншу мову, скажімо C ++ ', з дещо іншими правилами. У C ++ 'дозволено створювати посилання, що не є const, зі значенням r. Тут немає нічого непослідовного чи неможливого.

Але це дозволило б зробити деякий ризикований код, коли програміст міг би не отримати те, що він задумав, і дизайнери С ++ справедливо вирішили уникнути цього ризику.


0

Посилання - це "приховані вказівники" (не нульові) на речі, які можуть змінюватися (lvalues). Ви не можете визначити їх як константу. Це має бути річ "змінної".

РЕДАГУВАТИ ::

Я думаю

int &x = y;

як майже еквівалент

int* __px = &y;
#define x (*__px)

де __px- свіже ім'я, і #define xпрацює лише всередині блоку, що містить декларацію про xпосилання.


1
Чому ви можете, якщо посилання є const:)
Майкл Крелін - хакер

Але прикладу плаката не булоconst
Базиль Старинкевич

Так, я мав на увазі ваше формулювання "посилання - це вказівки на те, що може змінитись" - мова йде про недорогі посилання.
Михайло Крелін - хакер

" Посилання - це" приховані вказівники " " неправильно " на речі, які можуть змінити " неправильні " речі, які можуть змінитися (lvalues). " Неправильно
curiousguy

@Loki: не могли б ви пояснити більше?
Василь Старинкевич
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.