Chapel 中的行为“ref”和“const ref”

问题描述 投票:0回答:1

我试图理解

ref
const ref
应用于复合类型成员(例如记录)的行为。这里,可以假设它们的行为类似于 C++ 中的
auto&
const auto&
吗?即,即使对于
const ref
情况也不会创建副本?我想知道在某些情况下,编译器是否可以通过优化为
const ref
创建临时变量(尽管我猜这不会发生)。

为了获得一些经验,我尝试了以下代码并确认这个简单案例的地址是相同的。

use CTypes;

record Foo {
  var n = 100;
}

var foo: Foo;
writeln("foo.n  : addr = ", c_ptrToConst(foo.n));

ref n_ref = foo.n;
writeln("n_ref  : addr = ", c_ptrToConst(n_ref));

const ref n_cref = foo.n;
writeln("n_cref : addr = ", c_ptrToConst(n_cref));
(Result)
foo.n  : addr = 0x654816445110
n_ref  : addr = 0x654816445110
n_cref : addr = 0x654816445110

另外,为了检查数据的地址,在CTypes模块中使用

c_ptrToConst()
来编写类似于C++中的以下代码是否合理?

#include <iostream>
using namespace std;

struct Foo {
    int n = 100;
};

int main() {
    Foo foo;
    cout << "foo.n  : addr = " << &foo.n << endl;

    auto& n_ref = foo.n;
    cout << "n_ref  : addr = " << &n_ref << endl;

    const auto& n_cref = foo.n;
    cout << "n_cref : addr = " << &n_cref << endl;
}

一个相关的问题是:鉴于

ref
const ref
不进行复制,直接使用数组组件(例如
foo.arr
)或使用
ref
变量(
ref arr = foo.arr
)之间是否有性能差异用于执行相同的数组计算? (这里,
foo
应该有一个数组组件
arr
。)

constants ref chapel
1个回答
0
投票

在我看来,你的想法是正确的。 我认为 Chapel 中的

ref
const ref
就像 C 指针,但不需要
*
来取消引用或
&
来建立。 初始化它会将其指向某个东西(并且以后不能将其重新指向其他东西),并且随后对它的引用就像对该指针的取消引用一样。

由于 Chapel 支持分布式内存编程和全局命名空间,Chapel 引用可以引用存储在远程内存中(例如,远程计算节点上)的数据以及本地存储的变量,这使得它们比 C/C++ 更强大。

请注意,虽然您的示例使用 Chapel 的类型推断,这使得它们类似于您在 C++ 中提到的

auto
情况,但可以键入 Chapel 中的
ref
声明。 例如:

var x = 42;
ref y: int = x;

在这里,Chapel 推断

x
是一个
int
,因为它是用
int
文字初始化的。 虽然
y
可以类似地从 x 的类型推断出来,但在这里我断言它是
ref
int
。 虽然这在像这样的小情况下很明显,但在初始化表达式更复杂的情况下,这种类型注释可以作为文档或代码安全断言很有帮助。

我相当确定,今天 Chapel 编译器不会创建

const ref
引用的变量的深层副本,如果我们将来要更改此设置,我会感到惊讶。 具体来说,这样做似乎与用户明确要求的内容相矛盾。 如果 Chapel 将来这样做,我预计只会在它作为优化的情况下,用户无法确定我们已经这样做了(比如您使用
c_ptrToConst()
.

对于您的其他问题:

  • 对于记录来说,使用

    c_ptrTo()
    /
    c_ptrToConst()
    c_addrOf()
    /
    c_addrOfConst()
    是获取指向 Chapel 变量的 C 指针/const 指针的合理且等效的方法。 如您所知,对于其他类型,两者可能有所不同。 例如,对于本地连续数组,
    c_ptrTo()
    将返回指向数组缓冲区中第一个元素的指针,而
    c_addrOf()
    将返回指向数组元数据的指针。

  • 对于记录字段的

    ref
    ,我通常不希望使用
    foo.field
    refToField
    访问字段之间存在太大的性能差异,无论字段的类型如何。 我可以想象潜在差异的一种情况是,如果记录是静态分配的,则编译器知道
    foo.field
    的确切地址,但必须取消引用
    refToField
    的逻辑指针才能到达它。 但实际上,我预计这些情况不会经常出现,并且差异可以忽略不计。 具体来说,我经常使用
    ref
    const ref
    作为为更复杂的表达式创建简写的方法。

    裁判可以相当 有价值的是当表达式的位置对于 计算。 例如,像

    A[i, j][k]
    这样的复杂数组表达式将 往往涉及地址算术和指针取消引用,例如存储 如果要使用该元素,则对该元素的引用可能很有价值 在一段代码中多次出现。 同样,
    ref
    也很有用 当通过多个其他类字段(例如,二叉树中的
    root.left.right.right
    )访问一个类并且需要访问该类时 场几次。 在这两种情况下,
    ref
    都会给你们两个 表达式的简写以及直接指向其的更便宜的方法 内存中的位置。

© www.soinside.com 2019 - 2024. All rights reserved.