В чем разница между константой x и &xx?

285
20 декабря 2016, 22:49

В чем разница между константой x и &xx?

#include <iostream>
using namespace std;
int main() {
    const int x = 2;
    const int &xx = 3;
    cout << x << endl;
    cout << xx << endl;
    return 0;
}

Зачем нужен &?

Answer 1

Семантически эти два объявления различны

const int x = 2;
const int &xx = 2;

В первом случае объявляется константный объект, который инициализируется целочисленным литералом. Для него может даже не выделяться память, если не требуется обращение к памяти объекта. Компилятор может использовать значение этого константного объекта на этапе компиляции. Например,

const int x = 2;
int a[x];

Размер объявленного массива известен на этапе компиляции.

Что касается данного объявления

const int &xx = 2;

то здесь сначала создается временный объект для значения выражения 2, и затем на этот временный объект определяется ссылка. Где разместится в памяти этот временный объект - это будет известно на этапе выполнения программы. Заметьте, что сам временный объект не является константным. Это просто результат вычисления выражения, состоящего из одного операнда - целочисленного литерала 2.

В связи с этим имеется различная реакция компиляторов на использование ссылки xx.

Так, например, компилятор MS VC 2016 Community не компилирует следующий фрагмент кода

const int &xx = 2;
int a[xx];

Сообщение об ошибке

Ошибка C2131 выражение не определяется константой 623

Как я думаю, MS VC++ 2016 Community в данном случае ориентируется на следующее положение стандарта C++ о константных выражениях (5.20 Constant expressionю, п. №2)

  • a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or

Обратите внимание, что указано, что должна иметь место ссылка на константный объект, в то время как временное выражение, которым инициализируется ссылка вышепоказанного фрагмента кода, является не константным. Поэтому компилятор выдает сообщение об ошибке.

Этот же фрагмент кода успешно компилируется на www.ideone.com . Этот компилятор, по всей видимости, основывается на другом подпункте данного пункта стандарта C++

  • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

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

Так что если покопаться в стандарте C++, а также посмотреть на поведение компиляторов, то различия будут явными.:)

Answer 2

const int &xx = 3; - это ссылка на константное значение типа int. Откровенно говоря, рассказывать, что такое ссылка в C++, достаточно долго, поэтому позвольте ограничиться этим кратким ответом, отправив вас к соответствующей литературе.

Ссылка - это как бы псевдоним переменной, так сказать, альтернативное имя. В вашем конкретном случае поменять значение 3 просто так нельзя - это константа, поэтому и ссылка на это значение допустима только как на const int.

Answer 3

Разница на уровне машинного кода:

gcc 6.x

    // const int x = 2;
    mov     DWORD PTR [rbp-4], 2
    // const int &xx = 3;
    mov     eax, 3
    mov     DWORD PTR [rbp-20], eax
    lea     rax, [rbp-20]
    mov     QWORD PTR [rbp-16], rax

gcc 4.5.x

   // const int &xx = 3;
   mov     DWORD PTR [rbp-8], 3
   lea     rax, [rbp-8]
   mov     QWORD PTR [rbp-16], rax

Очевидно, что вторая инструкция [const int &xx = 3;] более дорогая, нежели первая. Ваш кэп.

Массив размером с x ? Пожалуйста. Ни одной ассемблерной инструкции - при условии, что мы его в дальнейшем никак не используем.

Массив размером с xx при условии, что мы его никак не используем. Пожалуйста.

    // gcc 6.x - int arr[xx];
    // комментарии излишне
    mov     rax, QWORD PTR [rbp-16]
    mov     eax, DWORD PTR [rax]
    cdqe
    sub     rax, 1
    mov     QWORD PTR [rbp-24], rax
    mov     rax, QWORD PTR [rbp-16]
    mov     eax, DWORD PTR [rax]
    cdqe
    mov     r8, rax
    mov     r9d, 0
    mov     rax, QWORD PTR [rbp-16]
    mov     eax, DWORD PTR [rax]
    cdqe
    mov     rsi, rax
    mov     edi, 0
    mov     rax, QWORD PTR [rbp-16]
    mov     eax, DWORD PTR [rax]
    cdqe
    sal     rax, 2
    lea     rdx, [rax+3]
    mov     eax, 16
    sub     rax, 1
    add     rax, rdx
    mov     edi, 16
    mov     edx, 0
    div     rdi
    imul    rax, rax, 16
    sub     rsp, rax
    mov     rax, rsp
    add     rax, 3
    shr     rax, 2
    sal     rax, 2
    mov     QWORD PTR [rbp-32], rax 
READ ALSO
Что такое standard-layout в C++ и зачем он нужен?

Что такое standard-layout в C++ и зачем он нужен?

Читал на английском, но так и не смог разобраться

260
Определение типа

Определение типа

Как определить тип результата арифметического выражения?

211
Реализовать иерархию классов [требует правки]

Реализовать иерархию классов [требует правки]

Реализовать иерархию классовВ каждом производном классе присутствует - конструктор инициализации, методы ввода-вывода данных, метод вычисления...

311