Передача массива по ссылке - PullRequest
1 голос
/ 02 апреля 2010

Ref. на мой последний пост и комментарий Sellibitze к этому посту о передаче массива по ref, а не по значению, почему при передаче массива компилятором значение может выводить аргументы, но не будет делать Я передаю его по значению?

template<class T,int row, int col>
void invert(T (&a)[row][col]) //NOTE AMPERSAND

в основном с объявлением выше, я могу позвонить:

int main(int argc, char* argv[])
{
invert(a);//HERE ARGUMETS ARE AUTOMATICALLY DEDUCED
}

но без амперсанда я бы назвал это так:

 int main(int argc, char* argv[])
    {
    invert<int,3,4>(a);
    }

@ Пол. Просто чтобы было ясно, когда я объявляю fnc:

void f(int a[]);//I'm passing a pointer

но когда я заявляю:

void f(int &a[]);//I'm passing a ref?

Правильно ли я понимаю это сейчас?

Ответы [ 3 ]

3 голосов
/ 02 апреля 2010

Это потому, что когда вы передаете массив «по значению», он распадается на указатель. То есть вы фактически передаете указатель на первый элемент без информации о размере.

Когда у вас есть такая подпись:

 void foo(int arr[10]);

, тогда значение 10 полностью игнорируется, и вы можете передавать ему массивы целых чисел любого размера. Это точно так же, как

 void foo(int arr[]);

или

void foo(int* arr);

Как видите, информация о размере не сохраняется, и поэтому ее нельзя использовать для определения размера массива.

При двумерном массиве первое измерение затухает. Например: массив из 10 массивов из 20 целых чисел (int arr[10][20]) распадается на указатель на массивы из 20 целых чисел (int (*arr)[20]) и т. Д., Поэтому значение 10 не может быть выведено, но размер второго измерения (20) равен может быть выведен.

template<class T,int row, int col>
void foo(T (&a)[row][col]) { }

template <class T, int col>
void bar(T arr[][col]) {}

int main()
{
    int a[10][20];
    foo(a);
    bar(a);
}

Когда вы передаете что-либо по ссылке, тип сохраняется, массивы не исчезают, и вся информация о размере остается доступной.

1 голос
/ 02 апреля 2010
void f(int &a[]); // I'm passing a ref?

Нет, здесь вы пытаетесь передать массив ссылок, которых нет в системе типов. У вас может возникнуть желание написать следующее:

void f(int (&a)[]);

Но ссылки на массивы с неизвестной границей не допускаются в качестве параметров функции.


Когда вы объявляете параметр функции как массив из n измерений, он переписывается компилятором как указатель на массив из n-1 измерений. Следующие подписи эквивалентны:

void fun(int x[][10]);
void fun(int x[2][10]);
void fun(int x[99][10]);
void fun(int (*x)[10]);

Граница первого измерения игнорируется и поэтому не может быть выведена из механизма шаблонов.

Что вы можете сделать, это передать указатель на весь двумерный массив:

template <class T, int row, int col>
void invert(T (*a)[row][col])
{
    std::cout << row << " x " << col << std::endl;
    T first_entry = (*a)[0][0];
}

int main(int argc, char* argv[])
{
    int a[10][20];
    invert(&a);
}

Это работает, как и ожидалось, но, как вы можете видеть, синтаксис немного неуклюж с обеих сторон.

1 голос
/ 02 апреля 2010

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

Я не совсем понимаю, что вы подразумеваете под "выводить аргументы"; Вы имеете в виду общий размер массива? Если да, то если вы передадите его по указателю, он потеряется, потому что указатели не несут такую ​​информацию.

В любом случае я настоятельно рекомендую использовать std::vector вместо простых старых массивов C; много меньше головных болей! По умолчанию они передаются по значению (как и следовало ожидать); при желании их можно легко передать по ссылке и по указателю, и они никогда не потеряют такую ​​информацию, как размер массива. Они также защищены от переполнения буфера и его потери, и они автоматически увеличиваются при добавлении новых элементов.

...