C++ 通过引用传递数组

Posted

技术标签:

【中文标题】C++ 通过引用传递数组【英文标题】:C++ pass an array by reference 【发布时间】:2012-04-17 23:25:36 【问题描述】:

这是否允许通过引用传递数组?

 void foo(double& *bar) 

似乎我的编译器说不。为什么?通过引用传递数组的正确方法是什么?还是变通?我有一个数组参数,我的方法应该修改,然后我应该检索。或者,我可以让这个数组成为一个类成员,它工作得很好,但它对我的代码的其他部分有很多缺点(我想避免)。

感谢和问候。

【问题讨论】:

检查clockwise spiral rule。 您是否考虑过使用std::vector 或类似名称? @moooeeeep std::vector 如果大小是动态/未知的,显然是优越的,但在大小始终相同的情况下,这将是矫枉过正,取而代之的是 std::array 解决了语法上的丑陋,而还赋予价值语义。 也可以关注en.cppreference.com/w/cpp/utility/functional/reference_wrapper 为什么不只是 void foo(double bar[ ]) ?如果您愿意,您还可以将数组的长度提供为 void foo(double bar[2])。除非对于复杂类型,需要避免使用复制构造函数。 【参考方案1】:

数组只能通过引用传递,实际上:

void foo(double (&bar)[10])


这会阻止您执行以下操作:

double arr[20];
foo(arr); // won't compile

为了能够将任意大小的数组传递给foo,请将其设为模板并在编译时捕获数组的大小:

template<typename T, size_t N>
void foo(T (&bar)[N])

    // use N here

你应该认真考虑使用std::vector,或者如果你有支持c++11的编译器,std::array

【讨论】:

“不过,一旦传递给foo,数组就会衰减为指针”。不,它没有,因为您只能传递一个包含 10 个元素的数组,所以您不需要有关大小的更多信息。 (再一次,您不能将数组传递给void foo( double*&amp; );隐式转换的结果是一个右值,不能用于初始化对非常量的引用。您必须使用@987654329 @. 太棒了 :) 这正是我想要的。我在模板中使用void foo(T &amp;bar[N]) - 但这实际上意味着“引用数组”而不是“对数组的引用”。 如果这样的函数已经存在,而你所拥有的只是一个std::vector(大小正确),你将如何将向量的内容(可能通过std::vector::data()获得)转换为这个数组类型?类型参数中固定数组大小的语法是什么(即与static_cast&lt;&gt;一起使用)? @meowsqueak 你不会,因为演员会有未定义的行为,AFAICT;我可以看到reinterpret_cast 中没有允许将动态分配的数组(分配后没有内在大小)视为具有固定大小的自动数组。此外,这是一个错误的问题:正确的问题是“我如何重构我的代码以使用这两种类型的容器?”,答案是模板和迭代器/范围,或者既然你说大小是固定的,一个函数只需要一个数据指针/引用并对大小进行硬编码(或者如果大小可能不同,则使用像span 这样的数据/大小适配器) 为什么不直接使用 void foo(double bar[ ])?如果您愿意,您还可以将数组的长度提供为 void foo(double bar[2])。除非对于复杂类型,需要避免使用复制构造函数。【参考方案2】:

是的,但是当参数匹配一个引用时,隐式数组 指针不是自动的,所以你需要这样的东西:

void foo( double (&array)[42] );

void foo( double (&array)[] );

但是请注意,在匹配时,double [42]double [] 是 不同的类型。如果您有一个未知维度的数组,它将 匹配第二个,但不是第一个,如果你有一个 42 的数组 元素,它将匹配第一个 而不是第二个。 (后者是, 恕我直言,非常违反直觉。)

在第二种情况下,您还必须传递维度,因为 一旦进入函数内部,就无法恢复它。

【讨论】:

第二个不能为我编译。 对我来说也不是。我不知道这是由于编译器错误还是我忽略的标准中的某些东西。我从来没有真正想要这样做。 (如果维度是模板参数,第一个非常有用,因为编译器会为您计算出正确的维度。) 我不相信第二个例子是有效的符合标准的 C++。顺便说一句,它不能与 GCC 4.8 或 Clang 3.4 一起编译。我认为需要模板大小。 @Ricky65 原来如此。我想知道为什么。通常允许对不完整类型的引用作为函数参数。 (当然,在这种情况下,类型在完成时会发生变化:double []double [42] 是两种不同的类型。因此,您唯一可以传递给后一种形式的就是一个长度未知的数组,例如 @ 987654327@ 之类的。这严重限制了可用性。)【参考方案3】:

当您使用 C++ 时,这里仍然缺少的强制性建议是使用 std::vector&lt;double&gt;

您可以通过引用轻松传递它:

void foo(std::vector<double>& bar) 

如果您有 C++11 支持,还请查看 std::array

供参考:

http://de.cppreference.com/w/cpp/container/vector http://de.cppreference.com/w/cpp/container/array

【讨论】:

:-) 是的。 std::vector 通常是最好的解决方案。但也有例外。【参考方案4】:

如果你只想修改元素:

void foo(double *bar);

够了。

如果要将地址修改为(例如:realloc),但对数组不起作用:

void foo(double *&bar);

是正确的形式。

【讨论】:

除非你不能将数组传递给后者。他问的是数组,而不是指针。 @JamesKanze:是的。第二种情况不适用于堆栈上的数组,在这种情况下,他应该使用第一种形式。 第二种情况不适用于数组,句号。只有当你有一个指针类型的实际变量时它才会起作用。【参考方案5】:

8.3.5.8 如果参数的类型包括“指向 T 的未知边界数组的指针”或“引用”形式的类型 到 T 的未知边界数组,”程序格式错误

【讨论】:

【参考方案6】:

就像其他答案所说,将&amp; 放在* 之后。

这提出了一个有趣的观点,有时可能会令人困惑:类型应该从右到左阅读。例如,这是(从最右边的* 开始)指向一个指向 int 的常量指针的指针。

int * const *x;

因此,您所写的将是指向引用的指针,这是不可能的。

【讨论】:

更改顺序仍然不允许他传递数组。它需要一个实际的指针对象,而不是转换的结果。【参考方案7】:

在这里,Erik 解释了通过引用传递数组的各种方式:https://***.com/a/5724184/5090928。

同样,您可以像这样创建一个数组引用变量

int arr1[] = 1, 2, 3, 4, 5;
int(&arr2)[5] = arr1;

【讨论】:

以上是关于C++ 通过引用传递数组的主要内容,如果未能解决你的问题,请参考以下文章

如何通过引用从 c# 到 c++ 传递字节数组

C++ 值传递指针传递引用传递详解

C++ 通过引用传递向量字符指针

通过引用c ++传递数组

C语言有引用传递吗

C ++通过引用其他类传递二维数组