How would you handle creating objects within a loop, adding them to a list, then returning that list?

Normally let's say you have a pattern where you call a function, and the function returns that object, then uses it, I would create the object before calling the function, lend it to the function, then it'll return and the whole thing is stack-allocated and therefore faster.

However, if you create a list of objects within a for loop, then return them, then the stack is popped, they are destroyed and there is no way to access them. Therefore, cannot stack alloc and have to Box them instead, add to the list, and return the list of Boxes. (Right? Or is that also not allowed.. not sure how that can be memory safe)

How would you handle a situation like this?

When you push something onto a Vec, it is placed in a heap buffer owned by the Vec. This way, you don't need to create a separate box on the heap for each item; there's just one heap allocation for the entire collection. So this function, for example creates a single allocation large enough to hold 100 integers, and then returns the Vec which owns that allocation:

fn foo() -> Vec<i32> {
    (0..100).collect()
}

The same works with any type, not just integers:

struct User {
    id: u32,
    age: u32,
    name: String,
}

fn users(count: usize) -> Vec<User> {
    let mut v = Vec::with_capacity(count);
    for id in 0..count {
        v.push(User { id, age: 0, name: String::new() });
    }
    v
}

This function again creates just one heap allocation and returns a Vec that points to that allocation.

6 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.