通过引用传递数组

时间:2010-04-02 10:43:07

标签: c++ argument-passing

参考。对于我的last post和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);
    }

@Paul所以,只是在我宣布fnc时要说清楚:

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

但是当我宣布:

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

我现在能正确理解吗?

3 个答案:

答案 0 :(得分:3)

那是因为当你按“值”传递数组时,它会衰减到一个指针。也就是说,您实际上是在没有任何大小信息的情况下传递指向第一个元素的指针。

当你有这样的签名时:

 void foo(int arr[10]);

然后完全忽略值10,您可以将任意大小的int数组传递给它。它与

完全相同
 void foo(int arr[]);

void foo(int* arr);

如您所见,大小信息未保留,因此无法用于推断数组的大小。

使用二维数组,第一个维度衰减。例如:包含20个整数(int arr[10][20])的10个数组的数组衰减到指向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 :(得分:1)

您不能仅通过指针传递数组(当您将数组传递给函数时,它会自动转换为指针)。

我真的不明白“推论论证”是什么意思;你的意思是阵列的总大小?如果是,那么如果你通过指针传递它就会丢失,因为指针不带有那种信息。

无论如何,强烈建议使用std::vector而不是普通的旧C数组;更少头痛!它们默认按值传递(如您所料);如果你愿意的话,它们很容易通过引用和指针传递,并且它们永远不会丢失诸如数组大小之类的信息。它们还可以防止缓冲区溢出和下溢,并且当您添加更多元素时它们会自动增长。

答案 2 :(得分:1)

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]);

忽略第一个维度的边界,因此无法通过模板机制推断。

您可以做的是将指针传递给整个2D数组:

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);
}

这可以按预期工作,但正如您所看到的,双方的语法都有点笨拙。