1

有一个简单的例子:

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

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

4

3 回答 3

2

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

如果是因为没有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 接口泛型编译器错误

[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

于 2015-10-28T12:47:31.487 回答
1

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

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

于 2015-10-28T10:43:34.483 回答
1

Genie 列表实际上是一个Gee.List<T>“伪装”的类类型,因此它会被引用计数。

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

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

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

于 2015-10-28T10:30:12.927 回答