【问题标题】:Is it legal c++ to use reference as array/pointer?c++ 使用引用作为数组/指针是否合法?
【发布时间】:2021-07-03 09:47:21
【问题描述】:

我的团队(包括我自己)是 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++,即它是否保证指向数组引用的指针指向原始数组?

有什么理由为什么要这样做而不是直接使用指针而不是在中间使用引用?

【问题讨论】:

  • 这不是指向引用的指针。您不能将指针指向引用。 &amp;some_ref 其中some_ref 是一个引用创建一个指向任何引用所指的指针。
  • (我不知道你为什么要打扰 - 你的 C++ 可以直接调用 the_c_function 而无需经过 the_cpp_wrapper。)
  • 我相信这段代码是合法的,但你不应该使用它。相反,请使用template &lt;std::size_t N&gt; void the_cpp_wrapper(double (&amp;arr)[N]) { the_c_function(arr, N); }
  • @NathanOliver:这只是在没有明确原因的情况下强制长度为编译时常量。
  • dref 不是对数组的引用,而是对double 的引用。 &amp;drefdouble 的位置。如果引用的double 恰好是数组的第一个元素,那么&amp;dref 当然是该数组的第一个元素的位置。 (而且,正如已经指出的那样,整个舞蹈完全没有必要 - 只需 the_c_function(dbl_array, LEN)。)

标签: c++ pointers reference


【解决方案1】:

我的团队(包括我自己)是 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&lt;double*&gt; 来抛弃const-ness。

如果你想“全力以赴”使用 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。 (请注意,TSpan "can" 是 std::span&lt;int&gt;,这可能会导致一些晦涩的编译器错误;有一些方法可以解决这个问题,但它更像是 C++。)


没有直接关系,但您可能会发现 std::span 也很有用。

【讨论】:

  • 这是一些很好的信息,但并不能真正回答问题。获取引用/别名的地址很好——您只是简单地获取被引用/别名的地址。我认为令人困惑的是“&”的重载使用——在一种情况下,它用于声明引用,而在另一种情况下,它被用作“地址”运算符。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    抛开代码可读性的问题,

    是否保证指向数组引用的指针指向原始数组?

    是的,请参阅§ 5.5 表达式:

    如果表达式最初的类型为“引用T”([dcl.ref],[dcl.init.ref]),则在进行任何进一步分析之前,该类型将调整为T。表达式指定引用所指的对象或函数,表达式是左值或xvalue,具体取决于表达式。

    还有§8.3.2 参考:

    4   未指定引用是否需要存储。

    5   不得有对引用的引用,不得有引用数组,并且不得有指向引用的指针

    换句话说,“引用地址”不是一个东西。给定double&amp; dref,获取地址&amp;dref 将给出数组中原始元素的地址。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-05
      • 2020-07-31
      • 2015-04-07
      • 2012-05-06
      • 2011-06-04
      • 1970-01-01
      • 1970-01-01
      • 2011-09-18
      相关资源
      最近更新 更多