Why am I copying?

In my program, I have two types of structs, one with a very longvector, and another that holds a view of a sub-part of the vector of another, reshaped to a matrix.

In principle this should work:

function reshapeView(vec, start, length, width)
    return reshape((@view vec[start:(start + width*length - 1)]), length, width)
end

struct A
      vec
end

struct B
      mat
end

a = A(rand(100))

b = B(reshapeView(a.vec, 3, 3, 3))

Now b holds a view to 9 elements of a.vec, starting at index 3, reshaped to a 3x3 matrix as expected. If I change something in a.vec, it is reflected in b.mat. However, if I now define

struct C{T,N}
      arr::Array{T,N}
end

C(vec::Vector{T}) where T = C{T,2}(reshapeView(vec, 3, 3, 3))

c = C(a.vec)

suddenly c holds a copy of the elements, instead of a view. Where am I implicitly copying?

In the implicit convert(Array{T,N}, ...) in the constructor of C. Note typeof(r) below.

julia> r = reshape(view(rand(9), :), 3, 3)
3×3 reshape(view(::Vector{Float64}, :), 3, 3) with eltype Float64:
 0.466486  0.796616   0.138344
 0.882214  0.651785   0.149842
 0.744935  0.0729783  0.0731422

julia> convert(Matrix{Float64}, r)
3×3 Matrix{Float64}:
 0.466486  0.796616   0.138344
 0.882214  0.651785   0.149842
 0.744935  0.0729783  0.0731422
2 Likes

If you want to keep all the type information to specialise on and avoid the copy, use:

struct C{T,N,A<:AbstractArray{T,N}}
    arr::A
end

You should be able to just pass the array into the constructor without needing to specify T or N:

C(vec::Vector) = C(reshapeView(vec, 3, 3, 3))
1 Like