#Freeing ArrayList data
1 messages · Page 1 of 1 (latest)
need to also free the individual strings after toOwnedSlice, which moves the items from the original list into the new slice (which is safe to do, since toOwnedSlice empties the original list, making the first deinit and free loop a noop)
When using a debugallocator you can see exactly which allocation leaked, which double freed, etc
yeah, that means you aren't freeing everything
you need to free everything at every exit point
defer inside a function doesn't propagate outside the function
defers always execute at scope exit
so you need to free those string elements in a loop wherever you're returning it to
gpa.deinit doesn't free your memory
it just tells you that you forgot to free your memory
If you are looking for a cyclical allocation deallocation pattern, like a game loop or a Web server http request, you'd be better off using an arena allocator, but you should get the basics of memory allocation first yeah
the allocator contract specifies that you should call free on memory you are no longer using. allocators depend on this to be able to re-use memory throughout the runtime of the program, instead of using infinitely more memory until you run out. allocators like debugallocator tell you that you forget to free memory
l.items is empty when you run that loop at the end
like I said, toOwnedSlice makes it empty
you have to free them from os
defer for (os) |str| gpa.free(str);
since the first defer for (l.items) |str| gpa.free(str); becomes a noop, you have to free the strings where they actually are
are you familiar with RAII and/or move semantics from C++, Rust, or any other language?
if not, I do second @fallow pollen's sentiment in trying to understand ownership and lifetimes on a more conceptual level
Yeah arenas just abstract it away way too much to the point where you start throwing them everywhere
In 0.15,this is the source code of toOwnedSlice
pub fn toOwnedSlice(self: *Self, gpa: Allocator) Allocator.Error!Slice {
const old_memory = self.allocatedSlice();
if (gpa.remap(old_memory, self.items.len)) |new_items| {
self.* = .empty;
return new_items;
}
const new_memory = try gpa.alignedAlloc(T, alignment, self.items.len);
@memcpy(new_memory, self.items);
self.clearAndFree(gpa);
return new_memory;
}
The clearAndFree call sets the items.len to 0, meaning the l for loop won't iterate through any items as the ownership of the items is passed to the owned slice with @memcpy.
The approach is what ink said, freeing the items from the new slice.
It's also best practice if you add a errdefer which frees the items from l in case you get any errors before you manage to call toOwnedSlice, such as an OOM in allocPrint. It's not necessary to do, but if you expect this to error out at some point without the error exiting the entire program, then you'll leak