1

Тема: Як влаштовані посилання?

Я прочитав, що посилання зазвичай реалізовуються через вказівники, але скільки тоді займає посилання?

int a = 0;
int *p = &a;

На x64 системі p буде розміром 8 байт. Як влаштовані посилання в аналогічній ситуації?

int a = 0;
int& r = a;

Скільки буде місця займати r як посилання?
І, яким ще методом можуть бути реалізовані посилання?

Подякували: leofun011

2

Re: Як влаштовані посилання?

Посилання - це синтаксичний цукор для вказівників, вони лише гарантують, що там не буде NULL (якщо, звісно, ви його навмисно туди не запхали). Тобто ті самі 8 байтів і буде: https://ideone.com/oi9y3N

Прихований текст
#include <iostream>

using namespace std;

class PtrHolder
{
    private:
    char *x_;
    public:
    PtrHolder(char *x): x_(x) {}
    void print(){cout<<"Ptr is "<<*x_<<endl;}
};

class RefHolder
{
    private:
    char &x_;
    public:
    RefHolder(char &x): x_(x) {}
    void print(){cout<<"Ref is "<<x_<<endl;}
};

class ValueHolder
{
    private:
    char x_;
    public:
    ValueHolder(char x): x_(x) {}
    void print(){cout<<"Value is "<<x_<<endl;}
};

int main() {
    char c = 'a';
    PtrHolder p(&c);
    RefHolder r(c);
    ValueHolder v(c);
    c = 'b';
    p.print();
    cout<<"PtrHolder is "<<sizeof(PtrHolder)<<" bytes"<<endl;
    r.print();
    cout<<"RefHolder is "<<sizeof(RefHolder)<<" bytes"<<endl;
    v.print();
    cout<<"ValueHolder is "<<sizeof(ValueHolder)<<" bytes"<<endl;    return 0;
}
Ptr is b
PtrHolder is 8 bytes
Ref is b
RefHolder is 8 bytes
Value is a
ValueHolder is 1 bytes
Подякували: mimik, leofun012

3

Re: Як влаштовані посилання?

Тобто в більшості випадків при передачі параметрів у функцію краще використовувати посилання?

4 Востаннє редагувалося wander (05.09.2020 22:44:00)

Re: Як влаштовані посилання?

mimik написав:

Скільки буде місця займати r як посилання?
І, яким ще методом можуть бути реалізовані посилання?

Посилання відрізняється від вказівників тим, що їх неможливо перепризначити. Це в багатьох випадках призводить до того, що компілятор має можливість інтерпретувати посилання просто як альтернативне ім'я вже існуючого об'єкта (або функції). Таке посилання буде вирішуватися на етапі компіляції і не буде займати пам'яті взагалі.

Ваш приклад якраз потрапляє в цю категорію.

У тих же випадках, коли це неможливо, тобто коли цільовий об'єкт посилання відомий тільки на етапі виконання, посилання зазвичай реалізується через звичайний вказівник та займає рівно стільки ж пам'яті, як і вказівник.

mimik написав:

Тобто в більшості випадків при передачі параметрів у функцію краще використовувати посилання?

Краще для чого? Для ефективності? Для зручності читання?

Передача параметрів в функцію - як раз той випадок, коли в загальному випадку компілятор на етапі компіляції не може знати, куди буде прив'язане посилання. Посилання-параметр зазвичай реалізується через звичайний вказівник. Так що ніякого "краще" з точки зору ефективності тут немає.

Можна хіба що лише зауважити, що в ряді окремих випадків компілятор зможе згенерувати більш ефективний код, спираючись на той факт, що посилання не може бути рівним нулю (nullptr), а вказівник - може.

Подякували: mimik, leofun01, koala, P.Y.4

5

Re: Як влаштовані посилання?

Для ефективності.
А чому ніякого краще немає? Якщо ви самі сказали, що на етапі компіляції компілятор може зробити оптимізації.
Тобто може бути таке що посилання якраз не вимагає ніякого місця в пам'яті або буде вести себе як вказівник.
Тобто в будь-якому випадку вона не гірше вказівника?

6

Re: Як влаштовані посилання?

mimik написав:

Тобто в будь-якому випадку вона не гірше вказівника?

"Не гірше" в якому сенсі, ще раз?

Посилання може бути гірше передачі за значенням. У ряді випадків. Чи запросто може бути гірше з точки зору зручності читання коду.

7

Re: Як влаштовані посилання?

шо?

8

Re: Як влаштовані посилання?

Прихований текст
ur_naz написав:

шо?

ти не хами людям, знов взявся за старе!

9 Востаннє редагувалося koala (06.09.2020 08:40:24)

Re: Як влаштовані посилання?

Оптимізатор може так само "з'їсти" і вказівник, якщо умови дозволяють.
Загальна практика - замість об'єктів і вказівників на них передавати за можливістю const &, а прості змінні - за значенням, хоча, звісно, залежить від ситуації і потреб.
А, ще є "розумні" вказівники unique_ptr та shared_ptr, їх теж можна активно використовувати (як і shared_ptr&, до речі).
Крім всього іншого, "ефективний" - це неоднозначне поняття. Програма може бути ефективною за пам'яттю, часом процесора, часом на розробку, іншими показниками. І в будь-якому разі не можна однозначно казати, що щось ефективніше, поза контекстом, треба дивитися конкретний код (а бажано - тестувати).

Подякували: leofun01, mimik2

10 Востаннє редагувалося wander (07.09.2020 13:15:53)

Re: Як влаштовані посилання?

koala написав:

Оптимізатор може так само "з'їсти" і вказівник, якщо умови дозволяють.

В загальному випадку точно так само не може.
Як мінімум через ці два конкретних фактори:

1. Незмінність прив'язки посилання протягом часу її життя;
2. Неприпустимість нульових посилань.

Ці фактори можуть бути використані для генерації більш оптимального коду з посиланнями, без необхідності якогось додаткового аналізу з боку компілятора. Аналогічні оптимізації з вказівниками теоретично можливі, але вимагають в загальному випадку глобального аналізу історії значення вказівника і повного знання картини aliasing (тобто можливі лише в деяких "хороших" випадках).

Прихований текст
#include <iostream>

void print(int* p) {
    if (p != nullptr)
        std::cout << "Not null";
    else
        std::cout << "Null";
}

void print_ref(int& r) {
    print(&r);
}

int main() {
    int a = 2020;
    print_ref(a);
}

Наприклад компілятор(GCC) породжує такий код для print_ref:

print_ref(int&):
        mov     edx, 8
        mov     esi, OFFSET FLAT:.LC0
        mov     edi, OFFSET FLAT:_ZSt4cout
        jmp     std::basic_ostream<char, std::char_traits<char> >& (truncated)

Тобто вбудовувавши код функції print в тіло функції print_ref компілятор відразу ж викинув з вбудованого коду непотрібне розгалуження if (p! = nullptr), тому що &r ніяк не може бути null.
https://godbolt.org/z/YTdnhT

Подякували: koala, leofun01, mimik3