使用引用作为数组/指针在C++中是否合法?

3

我的团队(包括我自己)是C++新手。我们的新开发项目中有一个需要与接受数组输入的C函数进行接口交互的C++函数。为了实现这一点,类似以下结构的内容被创建:

#include "stdio.h"

void the_c_function(double *array, int len)
{
   for (int i = 0; i < len; i++)
   {
      printf("%d: %g\n", i, array[i]);
   }
}

void the_cpp_wrapper(double& dref, int len)
{
   the_c_function(&dref, len);
}

int main()
{
   const int LEN = 4;
   double dbl_array[LEN] = { 3,4,5,6 };
   the_cpp_wrapper(dbl_array[0], LEN);
   return 0;
}

编译后,这将按预期工作:它会打印出数组的内容。
0: 3
1: 4
2: 5
3: 6

但我觉得这样做几乎不合法,或者至少是应该被反对的事情。

这是合法的C++代码吗?也就是说,指向数组引用的指针是否保证指向原始数组?

为什么要像这样使用它,而不是直接使用指针而不是中间使用引用呢?


2
这不是指向引用的指针。你不能取一个引用的指针。&some_ref,其中some_ref是一个引用,会创建一个指向引用所指向的任何内容的指针。 - user2357112
1
我不知道你为什么要费心 - 你的C++可以直接调用the_c_function,而不必经过the_cpp_wrapper - user2357112
我相信这段代码是合法的,但你不应该使用它。相反,你应该使用类似于 template <std::size_t N> void the_cpp_wrapper(double (&arr)[N]) { the_c_function(arr, N); } 的东西。 - NathanOliver
@NathanOliver:这只是强制长度成为编译时常量,没有明确的原因。 - user2357112
1
dref不是对数组的引用,而是对double的引用。&dref是该double的位置。如果所引用的double恰好是数组的第一个元素,则&dref当然是该数组第一个元素的位置。(正如已经注意到的那样,这整个过程是完全不必要的 - 只需执行the_c_function(dbl_array, LEN)即可。) - molbdnilo
显示剩余2条评论
3个回答

5
我的团队(包括我自己)对C++还不熟悉。[...] 这是应该被不鼓励的事情。
你现在应该养成使用标准C++库的习惯,对于你的情况最好的选择是std::vector
#include <stdio.h>
#include <stdlib>
#include <vector>

void the_c_function(const double *array, size_t len) {/*...*/}
void the_cpp_wrapper(const std::vector<double>& v)
{
   the_c_function(v.data(), v.size());
}
// ----------------------------
int main()
{
   const std::vector<double> dbl_array { 3,4,5,6 };
   the_cpp_wrapper(dbl_array);
   return EXIT_SUCCESS;
}

你还应该更清楚地了解 const double*double* 的区别,C++故意让你使用更冗长的 const_cast<double*> 来去除 const
如果你想要完全投入C++,你可以通过模板使 the_cpp_wrapper() 变得更通用一些。
template<typename TSpan>
void the_cpp_wrapper(const TSpan& v)
{
   the_c_function(v.data(), v.size());
}

使用这段代码,你可以将任何具有 data()size() 方法的内容传递给 the_cpp_wrapper
不是直接相关的,但你可能也会发现std::span很有用。

2
这是一些好的信息,但并没有真正回答问题。获取引用/别名的地址是可以的--你只是简单地获取被引用/别名的物体的地址。我认为令人困惑的是 '&' 的重载使用--在一种情况下它被用来声明一个引用,在另一种情况下它被用作"地址取值符号"。 - wcochran

1
除了代码可读性的问题之外,
“指向数组引用的指针是否保证指向原始数组?”
是有保证的。请参见§ 5.5 表达式:
如果一个表达式最初具有类型“对 T 的引用”([dcl.ref],[dcl.init.ref]),则在进一步分析之前将该类型调整为 T。该表达式指定由引用表示的对象或函数,并且该表达式是左值或右值,具体取决于表达式。
还有§8.3.2 引用:
4   不确定是否需要存储引用。
5   不得存在对引用的引用、引用的数组和指向引用的指针。
换句话说,“引用的地址”并不是一个东西;给定 double& dref,取地址 &dref 将会得到数组内原始元素的地址。

-1

是合法的,并且根据您的代码保证引用到数组中的原始元素。

有些人喜欢设计接口以强制调用者通过引用传递参数,以避免在传递指针时需要检查参数是否为 null 指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接