【问题标题】:Transfer ownership (Genie/Vala)转让所有权 (Genie/Vala)
【发布时间】:2015-10-28 10:01:29
【问题描述】:

有一个简单的例子:

struct MyStruct
    a: int
    b: int

def my_proc(): unowned list of MyStruct
    var result = new list of MyStruct
    var my_struct = MyStruct()
    for var i = 1 to 10
        my_struct.a = i
        my_struct.b = i*i
        result.add(my_struct)
    return result

init
    pass

在编译此代码时,会出现错误:“具有强引用的局部变量用作返回值和方法返回类型尚未声明转移所有权”。如何更改编译成功的代码?

【问题讨论】:

    标签: compiler-errors vala genie


    【解决方案1】:

    是什么让您认为返回值应该是无主的?

    如果是因为没有unowned,Vala 编译器给出了"error: 'MyStruct' is not a supported generic type argument, use '?' to box value types",那么你可以尝试使用list of MyStruct?。这个“盒子”[1][2] 基本 C 数据类型,因此可以在底层 GObject 类型系统中使用。

    如果是因为您阅读了教程和“弱引用”、“无主引用”、“所有权转移”和“指针”部分,那么我认为您应该将这些主题视为高级主题。我认为应该在某个时候将它们移到一个单独的页面,供想要深入了解 Genie 的人使用。

    Vala 编译器和 Genie 都有助于内存管理。这意味着一切都在后台为您处理好。 Vala 编译器具有合理的默认行为,因此您无需更改任何内容。

    作为 Genie 程序员,您应该了解与 C 库接口的可空类型,并且在创建循环引用时引用计数会造成内存泄漏[3]。除了查看 Genie 教程的该部分中的主题之外,对于那些真正想深入了解 Genie 如何工作和解决问题的人而言。

    结构可以被认为是对象的先驱。结构是一种复合数据类型。 Vala/Genie 中结构的内存由堆栈上的 C 编译器处理[4]。这可能会给他们带来性能优势。然而,一般来说,最好将类用于复合数据类型,因为它们更适合底层 GObject 类型系统。但是,如果您尝试大量优化某些代码以提高速度[5] 或与使用结构的 C 库接口,您可能希望使用结构。

    所以简短的回答是使用 Jens 的使用类的解决方案,除非你有充分的理由不这样做。

    [1] - https://developer.gnome.org/gobject/stable/gobject-Boxed-Types.html

    [2] - Vala interface generics compiler error

    [3] - https://wiki.gnome.org/Projects/Vala/ReferenceHandling

    [4] - https://wiki.gnome.org/Projects/Vala/Tutorial#Structs

    [5] - http://zee-nix.blogspot.co.uk/2008/09/think-before-you-create-gobjects.html

    【讨论】:

    • 我刚刚测试了struct MyStruct? 版本,惊讶地发现libgee 很好地处理了结构内存的破坏。
    • 很高兴知道,它也应该适用于 list of uint64? 之类的东西 structuint64 都是值类型的示例,因此不计入引用,而是由C编译器
    【解决方案2】:

    精灵列表实际上是“伪装”中的Gee.List<T>,这是一个类类型,所以它会被引用计数。

    此外,推断出的类型 var 变量目前始终是自有变量(Vala 错误跟踪器中有关于此的错误报告)。

    所以result 是对类实例的强引用。您不能将其作为无主引用返回。

    我强烈建议您对MyStruct 使用类而不是结构。

    否则你会遇到内存管理问题(结构不被引用计数)。

    您不必担心复制和所有权:

    class MyStruct
        a: int
        b: int
    
    def my_proc(): list of MyStruct
        var result = new list of MyStruct
        for var i = 1 to 10
            var my_struct = new MyStruct()
            my_struct.a = i
            my_struct.b = i*i
            result.add(my_struct)
        return result
    
    init
        pass
    

    编辑:如果您希望列表包含多个值,您还必须在循环内分配 my_struct!我已经更新了我的代码以反映这一点。

    【讨论】:

    • 说结构会导致内存管理问题,因为它们没有被引用计数可能会产生误导。我知道上下文是示例的MyStruct,但该语句暗示结构总会有问题。然而,Vala/Genie 中的结构是堆栈分配的,并在分配时复制。而类是堆分配的。栈会比堆小,而且内存分配策略更简单,所以更快,但只要能很好地理解差异,Genie 中的结构就可以使用。
    • 你说得对,“内存管理问题”有点太笼统了,但你现在的回答很好地补充了我的。
    【解决方案3】:

    在任何给定时间必须至少有一个对对象的引用。在这里,您创建了一个变量result,它引用了一个列表。当您退回它时,您坚持认为它是unowned list of MyStruct。这意味着返回没有引用并且result 超出范围,因此列表现在没有对它的引用并且将被释放。

    您实际上是在返回一个悬空引用。要么返回list of MyStruct,以便调用者有一个引用,要么将一个副本置于某个共享状态(全局变量或字段)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-28
      • 2018-08-08
      • 1970-01-01
      • 2012-02-02
      • 1970-01-01
      • 2014-07-21
      • 1970-01-01
      • 2012-05-10
      相关资源
      最近更新 更多