Почему не передаётся массив в функцию через указатель по ссылке (ссылочный указатель)?

Почему данная запись не работает?

#include <iostream>
using namespace std;

void foo(int *&pa){}

int main()
{
    int a[4]{};
    foo(a);
}

А когда я записываю так, то всё работает. В двух случаях же адрес указателя пытаюсь передать (значение указателя), т.е. сам указатель, в функцию, не создавая при этом новый, а просто ссылаясь на тот указатель. Имя массива может же служить указателем на его первый элемент, т.е. может хранить адрес первого элемента массива. Просто в первом случае я пропустил промежуточный указатель, т.к. имя массива тоже может служить им, но программа поломалась. Адрес то тот же передаю в функцию.

#include <iostream>
using namespace std;

void foo(int *&pa){}

int main()
{
    int a[4]{};
    int *x = a;
    foo(x);
}

Кстати, если создать динамический массив int *a = new int[4]; и потом передать a в функцию, то это тоже будет работать, что логично и работает адекватно. Интересует именно c++.


Ответы (2 шт):

Автор решения: LShadow77

В объявлении void foo(int *&pa){} функция foo() принимает в качестве параметра ссылку на указатель, т.е. на переменную в памяти, содержащую адрес массива. А в первом случае у вас нет этой переменной, вы пытаетесь передать непосредственный адрес массива, на который нельзя ссылаться по причине его физического отсутствия в памяти. По-этому и не работает.

Попытаюсь расширить объяснение: по ссылке в теле функции foo() вы можете изменить значение переданного указателя. Например:

#include <iostream>
using namespace std;

int b[5];

void foo(int *&pa)
{
    pa = b; //изменяем указатель по ссылке
}

int main()
{
    int a[4]{};
    int* p = a; 

    //сейчас p содержит адрес a
    foo(p);
    //а сейчас p содержит адрес b

    //а этот вызов не имеет смысла:
   foo(a);
   //...так как a - это непосредственный адрес массива a[], вы не можете его менять.
}

Как-то так.

P.S. И что тут кому не понравилось в моём объяснении??

→ Ссылка
Автор решения: HolyBlackCat

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

Указатель, получающийся в результате преобразования - rvalue (prvalue, если точнее). Грубо говоря это временный объект (хотя формально prvalue - вообще не объекты).

А неконстантные lvalue-ссылки можно инициализировать только lvalue. Отсюда ошибка.

→ Ссылка