【问题标题】:Return a constant reference to a member variable in Ada返回对 Ada 中成员变量的常量引用
【发布时间】:2018-06-12 09:37:52
【问题描述】:

我在 Ada 中有一个包含矩阵的类。我想实现一个将其作为constant access 类型返回的函数,只是为了能够将其作为只读值获取,但避免不必要的复制。

我已经通过返回对 Integer 的引用进行了尝试,仅用于测试目的:

package Tests_Package is
    type B is private;

    function Test(Self : in B) return access constant Integer;

    private
        type B is tagged
        record
            I : aliased Integer;
        end record;
end Tests_Package;

-------------------------------------------

package body Tests_Package is

    function Test(Self : in B) return access constant Integer is
    begin
        return Self.I'access;
    end Test;

end Tests_Package;

上面不会编译,错误是:non-local pointer cannot point to local object.

我的问题是:

为什么我会得到这个错误?

有什么方法可以实现我想要的,而不使用Unchecked_Access

我是否真的需要返回变量的引用,或者副本可以由 Ada 编译器优化出来?

【问题讨论】:

  • 副本可以优化掉。除非您确实无法满足预先指定的定量计时要求,否则您不必担心。
  • 在这种特殊情况下,函数的Self 参数是按值传递的。这意味着编译器creates 是所传递值的本地副本。当函数返回时,这个本地副本不再存在;因此,返回的地址无效。要使其正常工作,您可以将此值作为 access(在 C/C++ 中也称为指针)传递。

标签: pointers ada


【解决方案1】:

在 Ada 2012 中通过结合“Ada 2005 中引入的匿名访问类型”和“Ada 2012 中引入的 Implicit_Dereference 方面”引入了安全引用,并在此处简要介绍:

https://www.adacore.com/gems/gem-123-implicit-dereferencing-in-ada-2012

丹,在你的具体情况下

package Tests_Package is

   type Integer_Ref
     (Element : not null access constant Integer) is limited null record with
     Implicit_Dereference => Element;

   type B is tagged private;

   function Test (Self : aliased B) return Integer_Ref;

private

   type B is tagged
      record
         I : aliased Integer := 5;
      end record;

   function Test (Self : aliased B) return Integer_Ref is
      ((Element => Self.I'Access));

end Tests_Package;

并且是这样使用的:

with Tests_Package;
with Ada.Text_IO;

procedure Main is
   Variable : Tests_Package.B;

   Result   : Integer := 3 + Variable.Test;
begin
   Ada.Text_IO.Put_Line (Result'Img);
end Main;

如果您尝试通过“Variable.Test := 1;”设置私有变量您将收到编译时错误,因为您只有 Integer 的只读视图。

【讨论】:

    【解决方案2】:

    制作参数aliased:

    function Test(Self : aliased in B) return access constant Integer;
    

    (强制参数通过引用传递,ARM 6.2(3)

    【讨论】:

    • 您的代码 + 我的修改使用 GCC 6、7、8 和 GNAT CE 2016、2017、2018 编译。不知道有什么区别(当然,您的 B 型被标记,所以它是由 -无论如何都要参考。呵呵。)
    【解决方案3】:

    您收到错误消息是因为编译器无法保证在实体超出范围/消失后您不能保留对实体的引用。

    方面Implicit_Dereference 有一些技巧,应该可以解决您的问题。

    【讨论】:

      猜你喜欢
      • 2023-03-03
      • 1970-01-01
      • 2019-09-03
      • 2018-05-25
      • 1970-01-01
      • 2021-08-10
      • 1970-01-01
      相关资源
      最近更新 更多