The tensor has to own its shape
initCpu was taking *std.mem.Allocator. Why pass a reference? The field becomes std.mem.Allocator, the Zig value, copied. Then the real change: shape and strides were slices the caller still owned. After this, initCpu dupes both. deinit frees both, plus the data. The tensor is a thing you can return from a function without the caller’s stack arrays dying under it.
The size-mismatch error gets one name: DataSizeMismatch. You cannot hide a stride you do not own. You also cannot write a view against a layout the tensor forgot.