# What is the init pattern with self pointer

**URL:** <https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734>\
**Category:** Explain\
**Tags:** language, memory-management\
**Created:** [August 23, 2024, 6:37pm UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734 "2024-08-23T18:37:29Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![finlaydotb](https://ziggit.dev/user_avatar/ziggit.dev/finlaydotb/32/3462_2.png) [@finlaydotb](https://ziggit.dev/u/finlaydotb)\
**Post date:** [August 23, 2024, 6:37pm UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/1 "2024-08-23T18:37:30Z")

</div>

I have seen this init pattern in few places and I am not sure what is going on

```zig
    pub fn init(allocator: std.mem.Allocator) *Self {
        const self = allocator.create(Self) catch unreachable;
        self.* = Self{
            .allocator = allocator,
            .field1 = field1,
            .fieldN = fieldN
        };
        return self;
    }

```

First question is, how come de-referencing `self.*` works when self is not a reference?

Second question is, it looks like this should also lead to a dangling pointer? Given the fact that the memory is allocated in a function and a pointer to it is returned.

---

<div class="post-metadata">

**Author:** ![kristoff](https://ziggit.dev/user_avatar/ziggit.dev/kristoff/32/9_2.png) [@kristoff](https://ziggit.dev/u/kristoff)\
**Post date:** [August 23, 2024, 6:43pm UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/2 "2024-08-23T18:43:52Z")

</div>

The answer to both your questions lies in the behavior (and return type) of [`Allocator.create`](https://ziglang.org/documentation/master/std/#std.mem.Allocator.create)

---

<div class="post-metadata">

**Author:** ![pierrelgol](https://ziggit.dev/user_avatar/ziggit.dev/pierrelgol/32/10233_2.png) [@pierrelgol](https://ziggit.dev/u/pierrelgol)\
**Post date:** [August 23, 2024, 6:57pm UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/3 "2024-08-23T18:57:36Z")

</div>

To give you a translation in C, at least that how I view it :

```C
my_type_t *my_type_init(void)
{
	my_type_t *self = (my_type_t *)malloc(sizeof(my_type_t));
	if (!self)
		return (NULL);

	*self = (my_type_t) {
		.field1 = field1,
		.fieldN = fieldN,
	};
	return (self);
}

//you can also do it like that

my_type_t *my_type_init(void)
{
	my_type_t *self = (my_type_t *)malloc(sizeof(my_type_t));
	if (!self)
		return (NULL);
    self->field1 = field1;
    self->fieldN = fieldN;
	return (self);
}

```

1 - allocate sizeof(T);  
2 - copy the values to where self points to  
3 - return the pointer.

and if you want more clarity feel free to define your function as such

```zig
pub fn init(allocator: std.mem.Allocator) *Self {
        const self : *Self = allocator.create(Self) catch unreachable;
        self.* = Self{
            .allocator = allocator,
            .field1 = field1,
            .fieldN = fieldN
        };
        return self;
    }

```

---

<div class="post-metadata">

**Author:** ![dimdin](https://ziggit.dev/user_avatar/ziggit.dev/dimdin/32/1457_2.png) [@dimdin](https://ziggit.dev/u/dimdin)\
**Post date:** [August 23, 2024, 7:21pm UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/4 "2024-08-23T19:21:17Z")

</div>

> [@finlaydotb](#):
>
> First question is, how come de-referencing `self.*` works when self is not a reference?

It is a pointer. `self` type is `*Self`.

> [@finlaydotb](#):
>
> Second question is, it looks like this should also lead to a dangling pointer? Given the fact that the memory is allocated in a function and a pointer to it is returned

`allocator.create` creates a `Self` object in heap memory. The object is live until `allocator.destroy` is called to free the memory.  
`self.* = Self{...}` assigns the created `Self` data to the allocated memory pointed by `self`.

---

<div class="post-metadata">

**Author:** ![finlaydotb](https://ziggit.dev/user_avatar/ziggit.dev/finlaydotb/32/3462_2.png) [@finlaydotb](https://ziggit.dev/u/finlaydotb)\
**Post date:** [August 28, 2024, 6:54am UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/5 "2024-08-28T06:54:29Z")

</div>

> [@dimdin](#):
>
> `allocator.create` creates a `Self` object in heap memory. The object is live until `allocator.destroy` is called to free the memory.  
> `self.* = Self{...}` assigns the created `Self` data to the allocated memory pointed by `self`.

Thanks for this. Just some follow up questions.

Will the location always be heap memory when `allocator.create` is used? for instance if the allocator is a `std.heap.FixedBufferAllocator`? I looked at the documentation for allocator.create here [Zig Documentation](https://ziglang.org/documentation/0.13.0/std/#std.mem.Allocator.create) and it is not explicit that this would always be heap memory so just wanted to be sure (basically to avoid dangling pointers)

I also see that sometimes `allocator.alloc` is used instead of `allocator.create` and this allocates an array instead. Question is when using `allocator.alloc` are there things to keep in mind when returning the memory it allocates from a function? Basically is there any chances of having a dangling pointer?

Also looking at it’s documentation here [Zig Documentation](https://ziglang.org/documentation/0.13.0/std/#std.mem.Allocator.alloc) it does not really say if the memory allocated via alloc would be heap allocated or not. How may one be sure of this?

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [August 28, 2024, 10:12am UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/6 "2024-08-28T10:12:10Z")

</div>

> [@finlaydotb](#):
>
> I looked at the documentation for allocator.create here [Zig Documentation](https://ziglang.org/documentation/0.13.0/std/#std.mem.Allocator.create) and it is not explicit that this would always be heap memory so just wanted to be sure (basically to avoid dangling pointers)

I am not exactly sure what you mean with dangling pointers.  
When you allocate something you need to de-allocate it.  
When you allocate with `alloc` you free it with `free`.  
When you allocate with `create` you free it with `destroy`.

When you allocate something and you never de-allocate it, then you are leaking memory (which can be fine if your program is about to quit anyway), but by using `defer`/`errdefer` well can avoid leaks.  
(You also can write tests and use [checkAllAllocationFailures](https://ziglang.org/documentation/0.13.0/std/#std.testing.checkAllAllocationFailures))

Normally dangling pointer means that some data structure or piece of code holds on to a pointer that points to a piece of memory that was already freed. This is bad because you shouldn’t keep pointers to memory you don’t own, the allocator will give that memory to some other allocation call and that other piece of code doesn’t want some other part of the code messing with its memory.

If you mean something else with dangling pointer, please clarify.

> [@finlaydotb](#):
>
> Will the location always be heap memory when `allocator.create` is used? for instance if the allocator is a `std.heap.FixedBufferAllocator`?

No, `FixedBufferAllocator` gives you memory from a buffer with the interface of heap allocation, this is useful because it allows you to write code that is agnostic over whether the memory is on the stack or heap and allows you to use both with the same interface and without any code changes, but if you pass it a `FixedBufferAllocator` that is too small you will get an `error.OutOfMemory` because `FixedBufferAllocator` is limited in size, so you can only use that if failing allocation is okay or you are able to predict a size that is big enough.

There is also [StackFallbackAllocator](https://ziglang.org/documentation/0.13.0/std/#std.heap.StackFallbackAllocator) which will fallback to another allocator if it doesn’t fit in the specified size.

> [@finlaydotb](#):
>
> Also looking at it’s documentation here [Zig Documentation](https://ziglang.org/documentation/0.13.0/std/#std.mem.Allocator.alloc) it does not really say if the memory allocated via alloc would be heap allocated or not. How may one be sure of this?

It depends on the allocator and you know by reading the documentation and or code of the allocator.

It seems to me like you might have some misconception about memory, heap allocated memory isn’t magical, if you want heap memory you need to use an allocator that gives you heap memory. But sometimes you can use stack memory and it can be beneficial for performance.

It mostly depends on the lifetime of the memory and how big the needed memory is, whether using stack memory is an option.

---

<div class="post-metadata">

**Author:** ![dimdin](https://ziggit.dev/user_avatar/ziggit.dev/dimdin/32/1457_2.png) [@dimdin](https://ziggit.dev/u/dimdin)\
**Post date:** [August 28, 2024, 10:14am UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/7 "2024-08-28T10:14:26Z")

</div>

> [@finlaydotb](#):
>
> Will the location always be heap memory when `allocator.create` is used?

It depends on the allocator.

> [@finlaydotb](#):
>
> for instance if the allocator is a `std.heap.FixedBufferAllocator`?

FixedBufferAllocator returns memory from a buffer, that buffer might be in the stack.

> [@finlaydotb](#):
>
> Question is when using `allocator.alloc` are there things to keep in mind when returning the memory it allocates from a function?

allocator.alloc is used to allocate memory for multiple sequentially located objects (an array). The memory allocated with alloc vs create have no difference except that you need to call free for memory allocated using alloc and destroy for memory allocated using create.

[Page allocator](https://ziglang.org/documentation/master/std/#std.heap.page_allocator) and [General purpose allocator](https://ziglang.org/documentation/master/std/#std.heap.general_purpose_allocator) allocate from heap.  
See [Allocators in zig.guide](https://zig.guide/standard-library/allocators/) for more information.

---

<div class="post-metadata">

**Author:** ![finlaydotb](https://ziggit.dev/user_avatar/ziggit.dev/finlaydotb/32/3462_2.png) [@finlaydotb](https://ziggit.dev/u/finlaydotb)\
**Post date:** [August 28, 2024, 10:21am UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/8 "2024-08-28T10:21:42Z")

</div>

> [@Sze](#):
>
> If you mean something else with dangling pointer, please clarify.

Sorry maybe I am using the wrong terminology.

I am talking about the case where value is created within a function and a pointer to it is returned, but it’s lifetime is tied to to function, hence when the function goes out of scope, the reference returned is now garbage.

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [August 28, 2024, 10:40am UTC](https://ziggit.dev/t/what-is-the-init-pattern-with-self-pointer/5734/9 "2024-08-28T10:40:56Z")

</div>

In that case the term applies (I just didn’t think you were using it in that way for some reason) and in that case you need to use an allocator that gives you heap memory, which requires reading the documentation of the allocator.

But maybe we could get safety checks in the future which would be able to give error messages for these memory bugs, here is a related issue:

> <https://github.com/ziglang/zig/issues/2646>
>
> I'm new to zig and low level programming in general. Naturally when I encountere…d the code for setting up an allocater I tried to encapsulate it.
> 
> \`\`\`
> var direct = std.heap.DirectAllocator.init();
> defer direct.deinit();
> var arena = std.heap.ArenaAllocator.init(&direct.allocator);
> defer arena.deinit();
> \`\`\`
> 
> I tried to (in retrospect naively) create a struct to take care of the repetition in my tests:
> 
> \`\`\`
> const MyStruct = struct {
>     
> \_alloc1: \*std.heap.DirectAllocator,
> \_alloc2: \*std.heap.ArenaAllocator,
> 
> pub fn init() !MyStruct {
> var direct = std.heap.DirectAllocator.init();
> var arena = std.heap.ArenaAllocator.init(&direct.allocator);
> return MyStruct{
> .\_alloc1 = &direct,
> .\_alloc2 = &arena,
> };
> }
> pub fn deinit(self: MyStruct) void {
> self.\_alloc2.deinit();
> self.\_alloc1.deinit();
> }
> };
> \`\`\`
> 
> When using this I get a segfault though. 
> 
> In #zig @shawnl was helpful enough to explain the issue. The allocators are created on the stack of the \`init\` function and so the pointers to them that are set on the struct are invalid once the \`init\` function returns.
> 
> I am opening this issue because @shawnl claims there may be a way to figure out when such pointers are created and survive beyond the lifetime of the stack variables and for the compiler to raise an error.
