Что полезно в отношении параметра reference-to-array?

Недавно я нашел такой код:

typedef int TenInts[10];
void foo(TenInts &arr);

Что вы можете сделать в теле foo(), которое полезно, что вы не могли сделать, если объявление было:

void foo(int *arr);    // or,
void foo(int arr[]);   // or,
void foo(int arr[10]); // ?

Я нашел вопрос, который просит как передать ссылку на массив. Думаю, я спрашиваю почему.

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

Ответ 1

Параметр reference-to-array не позволяет разбить тип массива на тип указателя. т.е. точный тип массива сохраняется внутри функции. (Например, вы можете использовать трюк sizeof arr / sizeof *arr для параметра и получить счетчик элементов). Компилятор также проведет проверку типов, чтобы убедиться, что тип аргумента массива точно такой же, как тип параметра массива, т.е. Если параметр объявлен как массив из 10 целых чисел, аргумент должен быть массивом точно равным 10 ints и ничего больше.

Фактически, в ситуациях, когда размер массива фиксирован во время компиляции, использование объявлений параметров reference-to-array (или указателя-массива) может быть воспринято как первичный, предпочтительный способ передать массив. Другой вариант (когда тип массива разрешен для разложения на тип указателя) зарезервированы для ситуаций, когда необходимо передать массивы времени выполнения.

Например, правильный способ передать массив размера времени компиляции для функции

void foo(int (&arr)[10]); // reference to an array

или

void foo(int (*arr)[10]); // pointer to an array

Несомненно, неправильный способ заключается в использовании "затухающего" подхода

void foo(int arr[]); // pointer to an element
// Bad practice!!!

"Затухающий" подход должен быть обычно зарезервирован для массивов времени выполнения и обычно сопровождается фактическим размером массива в отдельном параметре

void foo(int arr[], unsigned n); // pointer to an element
// Passing a run-time sized array

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

Вышеприведенное является в основном прямым следствием более общего принципа. Когда у вас есть "тяжелый" объект типа T, вы обычно передаете его либо указателем T *, либо ссылкой T &. Массивы не являются исключением из этого общего принципа. У них нет причин быть.

Имейте в виду, что на практике часто имеет смысл писать функции, которые работают с массивами времени выполнения, особенно когда речь заходит об общих, библиотечных функциях. Такие функции более универсальны. Это означает, что часто есть веская причина использовать "разложившийся" подход в реальном коде жизни. Тем не менее это не оправдывает автора кода от распознавания ситуаций, когда размер массива известен во время компиляции и с использованием ссылки на -array соответственно.

Ответ 2

Одно отличие состоит в том, что он (предположительно) не может передать нулевую ссылку. Поэтому теоретически функции не нужно проверять, является ли параметр нулевым, тогда как параметр int * arr может быть передан null.

Ответ 3

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

template<class E, size_t size>
size_t array_size(E(&)[size])
{
    return size;
}

int main()
{
    int test[] = {2, 3, 5, 7, 11, 13, 17, 19};
    std::cout << array_size(test) << std::endl; // prints 8
}

Больше sizeof(test) / sizeof(test[0]) для меня; -)

Ответ 4

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

Ответ 5

Вы получаете больше семантического значения относительно ожидаемой функции.