Initializing dynamically allocated objects

G’day gentlefolks,

so, I was thinking. Normally, when you allocate a structure on the stack, or statically, the more or less established pattern is to use an init() method that will create the struct and take care of the initialisation. As a nice side effect, zig’s type checker will ensure that you leave no field uninitialized. Happy pandas all around.

But when you allocate a structure from the heap using someallocator.create(T), or as part of a container struct, things are not so clear cut. You will end up with an uninitialized piece of memory. Obviously it is not too hard to initialize that, but I was wondering, whether there is some sort of already established pattern for this sort of thing, similar to the init() method?

The two ways I see here is to either have a method that sets all fields individually. This would work, but would lead to multiple different intialization functions, which might cause problems when the struct changes. Or, you could just create an object on the stack using init(), and copy that into the heap-allocated object. That would work, I guess, and I lean towards that method.

Any other ideas?

Gnarz

I think that given that create only returns a pointer to the unitilized struct memory, you could then call the regular init function and assign its result to that memory:

const ptr = try allocator.create(Foo);
ptr.* = Foo.init(...);

Also, in the case of simple structs, one protection against the use of uninitialized fields could be giving them default values in the struct definition and then assigning a default instance to the pointer without an init function is easy.

const Foo = struct {
    a: u8 = 0,
    b: bool = false,
};
const ptr = try allocator.create(Foo);
ptr.* = Foo{};

But yes, in both cases there’s the danger of forgetting to assign an instance to the pointed-to memory and then using that uninitialized memory.

Maybe yet another option would be having an initAlloc function that will allocate and initialize the memory, returning the pointer:

fn initAlloc(allocator: Allocator, a: u8, b: bool) !*Foo {
    var ptr = try allocator.create(Foo);
    ptr.a = a;
    ptr.b = b;
    return ptr;
}
2 Likes

This sort of thing is usually named create instead of init.

There aren’t too many examples of this, but here’s one:

It initializes the struct like so:

There are more examples of create functions in std.Build but that API is a bit unique since it panics on OOM.

2 Likes

Thanks for your input. It is basically along the lines I was thinking. So I think I will go with

const ptr = try allocator.create(Foo);
ptr.* = Foo.init();

for the general case. This will also work for the create() method case, should I do that.

1 Like