#How to free memory from an ArrayList

1 messages · Page 1 of 1 (latest)

blissful wigeon
#

If I have a type that I need to call deinit on to free the memory it allocates, does array_list.deinit() free the memory the type allocated? Or do I have to do something as shown in the code block?

var output = std.ArrayList(T).init(allocator);
errdefer {
    var objects = output.toOwnedSlice();
    for (objects) |object| object.deinit(allocator);
    allocator.free(objects);
}

Thanks!

severe ice
#

The call to deinit will free whatever the ArrayList itself allocated. If T is an int, struct, or any other plain ol' value, it would have been copied into the ArrayList, and therefore freed with deinit.

If T is a pointer type however, and you had to allocate the pointed-to values yourself before appending them to the list, ArrayList.deinit will not assume control over those underlying values. You would have to free them yourself 🕊️

This is good because you might have allocated those pointed-to values with a different allocator altogether, or maybe you want them to live even after the list is gone.

#

In case you're wondering: deinit is not a magic name, it's just a convention, a commonly used name for tear-down. A call to a deinit function won't necessarily implicitly call more deinits. Best look at the code and doc comments to understand the expectations.

stark bobcat
#

Worth noting: if you're allocating a big nested datastructure which you need to free all at once, std.heap.ArenaAllocator might be useful :) an arena is a simple but useful allocator which allows quickly and easily freeing all the memory that's ever been allocated using it. In cases where I'm, for instance, parsing a complex file format, I normally put everything in an arena, which means that a) freeing at the end is fast and trivial and b) I don't need to worry about freeing precisely the right stuff in error cases (instead, just errdefer arena.deinit()!)

#

Also, why're you running toOwnedSlice on the arraylist in your freeing code? Just do this:

for (output.items) |obj obj.deinit(allocator);
output.deinit();

In case you weren't aware, you can of course access elements of an arraylist without converting it to a slice; items is part of its public API (which is also how you're expected to e.g. get its length if you need)

blissful wigeon
#

okay, I wasn’t sure if it would double free if I ran deinit on the items directly

pine nacelle
# blissful wigeon okay, I wasn’t sure if it would double free if I ran deinit on the items directl...

The important thing to understand is to think with data instead of objects.
What you've got is a region of memory that's been allocated, and you've got a sequence of objects laid out within it.
Freeing the region doesn't involve doing anything to the objects at all, by nature; deinitting the objects also has nothing to do with freeing the region, beyond the fact that you'd need to free the region -afterwards-, as it would be a UAF otherwise.