转让所有权(Genie/Vala)

Transfer ownership (Genie/Vala)

有一个简单的例子:

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

在编译这段代码的情况下,出现错误:"Local variable with strong reference used as return value and method return type has not been declared to transfer ownership"。如何修改编译成功的代码?

Genie 列表实际上是 "disguise" 中的 Gee.List<T>,它是 class 类型,因此它将被引用计数。

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

所以 result 对 class 实例的强引用。您不能 return 将其作为无主引用。

我强烈建议您使用 class 而不是 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!我已经更新了我的代码以反映这一点。

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

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

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

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

如果是因为您阅读了教程和有关 "Weak References"、"Unowned References"、"Ownership Transfer" 和 "Pointers" 的部分,那么我认为您应该将这些主题视为高级主题话题。我认为他们应该在某个时候被移动到一个单独的页面,供那些想要深入研究 Genie 的人使用。

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

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

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

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

[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