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*& )
;隐式转换的结果是一个右值,不能用于初始化对非常量的引用。您必须使用@987654329 @.
太棒了 :) 这正是我想要的。我在模板中使用void foo(T &bar[N])
- 但这实际上意味着“引用数组”而不是“对数组的引用”。
如果这样的函数已经存在,而你所拥有的只是一个std::vector
(大小正确),你将如何将向量的内容(可能通过std::vector::data()
获得)转换为这个数组类型?类型参数中固定数组大小的语法是什么(即与static_cast<>
一起使用)?
@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<double>
。
您可以通过引用轻松传递它:
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】:就像其他答案所说,将&
放在*
之后。
这提出了一个有趣的观点,有时可能会令人困惑:类型应该从右到左阅读。例如,这是(从最右边的*
开始)指向一个指向 int 的常量指针的指针。
int * const *x;
因此,您所写的将是指向引用的指针,这是不可能的。
【讨论】:
更改顺序仍然不允许他传递数组。它需要一个实际的指针对象,而不是转换的结果。【参考方案7】:在这里,Erik 解释了通过引用传递数组的各种方式:https://***.com/a/5724184/5090928。
同样,您可以像这样创建一个数组引用变量:
int arr1[] = 1, 2, 3, 4, 5;
int(&arr2)[5] = arr1;
【讨论】:
以上是关于C++ 通过引用传递数组的主要内容,如果未能解决你的问题,请参考以下文章