#Allocator destroy

1 messages · Page 1 of 1 (latest)

blazing root
#

So i am trying to free node of Circular linked list. but when i checked the CSLL object , node is still present.

pub fn SCLL(comptime DataType: type) type {
    return struct {
const SCLLNode = struct {
            value: DataType,
            next: ?*SCLLNode,

            fn init(allocator: std.mem.Allocator, value: DataType) !*SCLLNode {
                var node = try allocator.create(SCLLNode);
                node.value = value;
                node.next = null;
                return node;
            }
        };

        fn free(self: *Self) void {
            if (self.len > 0) {
                var temp = self.head;
                while (temp != null) {
                    const to_free = temp;
                    temp = temp.?.next;
                    self.allocator.destroy(to_free.?);
                    // self.len -= 1;
                }
                self.allocator.destroy(temp.?);
                // self.len -= 1;
            }
        }
tiny sleet
#

could you provide a full compilable example?
ideally also a failing test that you expect to succeed (or a passing test you expect to fail)

blazing root
#

my original free func

fn free(self: *Self) void {
            if (self.len > 0) {
                var temp = self.head;
                while (temp.?.next != self.head) {
                    const to_free = temp;
                    temp = temp.?.next;
                    self.allocator.destroy(to_free.?);
                    self.len -= 1;
                }
                self.allocator.destroy(temp.?);
                self.len -= 1;
            }
        }

My main func

var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    var a = [_]u8{ 1, 2, 3, 4, 5 };
    var scll: SCLL(u8) = undefined;
    try scll.init(arena.allocator(), &a);
    scll.print();
    scll.free();
    scll.print();
    std.debug.print("{any}", .{scll});
#

my output

The linked list is:
1 -> 2 -> 3 -> 4 -> 5 -> HEAD
The linked list is:
null
zig.SCLL(u8){ .allocator = mem.Allocator{ .ptr = anyopaque@7ffee9877ca0, .vtable = mem.Allocator.VTable{ .alloc = fn (*anyopaque, usize, u8, usize) ?[*]u8@103c960, .resize = fn (*anyopaque, []u8, u8, usize, usize) bool@103d040, .free = fn (*anyopaque, []u8, u8, usize) void@103d450 } }, .head = zig.SCLL(u8).SCLLNode{ .value = 1, .next = zig.SCLL(u8).SCLLNode{ .value = 2, .next = zig.SCLL(u8).SCLLNode{ ... } } }, .len = 0 }
#

see how .head instance varibale sill have nodes, I was expecting it to be null

#

I wrote same code in c , And it was null there

tiny sleet
# blazing root my output ``` The linked list is: 1 -> 2 -> 3 -> 4 -> 5 -> HEAD The linked list...

ah, okay two things:

  1. you're using an arena allocator, which means that the memory isn't actually freed until the arena.deinit() (technicially, freeing with an arena can actually free the memory, but only if you're freeing the last allocation that was made). This means that the memory is still alive after the scll.free() call. If you used a different allocator, then the print afterwards would likely crash/segfault
  2. allocator.destroy only frees memory, it doesn't do anything else. If you expect scll.head to be null after scll.free() then you need to set it null in your free implementation
blazing root
tiny sleet
#

something that might be helpful is to write a test case using std.testing.allocator, which will check for leaks/other memory problems automatically

just something simple like:

test "SCLL" {
    var a = [_]u8{ 1, 2, 3, 4, 5 };
    var scll: SCLL(u8) = undefined;
    try scll.init(std.testing.allocator, &a);
    scll.print();
    scll.free();
    scll.print();
    std.debug.print("{any}", .{scll});
}

would give you a better indication of if your code is buggy

tiny sleet
blazing root
#

ohh , from where can i learn about testing in zig?

tiny sleet
blazing root
tiny sleet
#

with anything else, free and destroy do nothing when using an arena

blazing root
tiny sleet
blazing root
tiny sleet
#

if you're creating/destroying a lot of one type, then there's also std.heap.MemoryPool which works kind of like an arena but destroy will free up that memory for re-use

#

internally, it's just an ArenaAllocator + a free list (a linked list of pointers to available memory)

blazing root
#

ohh, i will check into it. Probably create a better custom arena allocatorzerobeef .
Thank you mate!!

tiny sleet
#

np zeroLike