如何在 Zig 的 Comptime 中指定分配器?

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

在 Zig 中,我想在

comptime
指定一个分配器,以消除将分配器传递给每个需要它的函数所带来的额外开销。在下面的 MWE 中,我有一个类型生成器,它接受
comptime
ArenaAllocator
并返回一个类型,该分配器作为“静态”成员。该类型被实例化,称为
MyType
,然后使用之前指定的分配器初始化
MyType
的对象。

const std = @import("std");

fn MyTypeGen(comptime arena: *std.heap.ArenaAllocator) type {
    return struct {
        var allocator = arena.allocator();

        data: []const u8,

        pub fn init(data: []const u8) !@This() {
            const temp = try allocator.alloc(u8, data.len);
            @memcpy(temp, data);

            return .{ .data = temp };
        }
    };
}

pub fn main() !void {
    comptime var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();

    const MyType = MyTypeGen(&arena);

    const val = try MyType.init(&[_]u8{ 1, 2, 3 });

    std.debug.print("{}\n", .{val});
}

问题是上面的代码因分段错误而失败

Segmentation fault at address 0x7ff63e46b628
C:\Program Files\zig\lib\std\heap\arena_allocator.zig:171:39: 0x7ff63e3f2788 in createNode (Calculator.exe.obj)
        self.state.buffer_list.prepend(buf_node);
                                      ^
C:\Program Files\zig\lib\std\heap\arena_allocator.zig:184:29: 0x7ff63e3f216a in alloc (Calculator.exe.obj)
            (self.createNode(0, n + ptr_align) orelse return null);
                            ^
C:\Program Files\zig\lib\std\mem\Allocator.zig:225:53: 0x7ff63e4242dd in allocBytesWithAlignment__anon_6797 (Calculator.exe.obj)
    const byte_ptr = self.rawAlloc(byte_count, log2a(alignment), return_address) orelse return Error.OutOfMemory;
                                                    ^
C:\Program Files\zig\lib\std\mem\Allocator.zig:211:40: 0x7ff63e3f2e37 in allocWithSizeAndAlignment__anon_3321 (Calculator.exe.obj)
    return self.allocBytesWithAlignment(alignment, byte_count, return_address);
                                       ^
C:\Program Files\zig\lib\std\mem\Allocator.zig:129:41: 0x7ff63e3f11f3 in alloc__anon_3262 (Calculator.exe.obj)
    return self.allocAdvancedWithRetAddr(T, null, n, @returnAddress());
                                        ^
C:\...\src\main.zig:10:45: 0x7ff63e3f1044 in init (Calculator.exe.obj)
            const temp = try allocator.alloc(u8, data.len);
                                            ^
C:\...\src\main.zig:24:32: 0x7ff63e3f1486 in main (Program.exe.obj)
    const val = try MyType.init(&[_]u8{ 1, 2, 3 });
                               ^
C:\Program Files\zig\lib\std\start.zig:348:65: 0x7ff63e3f175c in WinStartup (Program.exe.obj)
    std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain());
                                                                ^
???:?:?: 0x7ffee8867343 in ??? (KERNEL32.DLL)
???:?:?: 0x7ffeea8426b0 in ??? (ntdll.dll)
run Program: error: the following command exited with error code 3:
C:\...\zig-out\bin\Program.exe
Build Summary: 3/5 steps succeeded; 1 failed (disable with --summary none)
run transitive failure
+- run Program failure
error: the following build command failed with exit code 1:
C:\...\zig-cache\o\03618dc1d07de7a2b7ce2381e69121e1\build.exe C:\Program Files\zig\zig.exe C:\... C:\...\zig-cache C:\...\AppData\Local\zig run

问题似乎在于 Windows 在运行时指定了支持

ArenaAllocator
的堆分配器,这意味着
comptime var arena
被错误地初始化。 Zig 一定不能抱怨编译时表面上的运行时依赖性,因此会出现段错误。

如何成功初始化

comptime
的竞技场分配器?

也欢迎在

comptime
指定分配器的替代方法,这些方法不需要以上述方式初始化分配器。

compile-time allocator zig
1个回答
0
投票

将分配器包装在自己的全局类型中似乎可行。

const std = @import("std");

const GlobalArena = struct {
    var global_arena: std.heap.ArenaAllocator = undefined;

    fn init(arena: std.heap.ArenaAllocator) void {
        global_arena = arena;
    }

    fn deinit() void {
        global_arena.deinit();
        global_arena = undefined;
    }

    fn allocator() std.mem.Allocator {
        return global_arena.allocator();
    }
};

fn MyTypeGen(comptime GlobalAllocator: type) type {
    return struct {
        var allocator = GlobalAllocator.allocator();

        data: []const u8,

        pub fn init(data: []const u8) !@This() {
            const temp = try allocator.alloc(u8, data.len);
            @memcpy(temp, data);

            return .{ .data = temp };
        }
    };
}

pub fn main() !void {
    GlobalArena.init(std.heap.ArenaAllocator.init(std.heap.page_allocator));
    defer GlobalArena.deinit();

    const MyType = MyTypeGen(GlobalArena);

    const val = try MyType.init(&[_]u8{ 1, 2, 3 });

    std.debug.print("{}\n", .{val});
}
$ zig version
0.12.0-dev.587+eb072fa52

$ zig build run
main.MyTypeGen(main.GlobalArena){ .data = { 1, 2, 3 } }
© www.soinside.com 2019 - 2024. All rights reserved.