NGHSS
NGHSS

Reputation: 61

Vector of vectors access to undefined reference

I am trying to create a vector of vectors since I need the data structure to have a fixed number of rows(6) but a variable number of columns. And in each of the units of the data structure, I want to store an instance of a structure. My code is:

struct abc
    a::Float64
    b::Float64
    c
end


k = Vector{Vector{abc}}(6);


for i = 1:6
   for j = 1:6
        aa, bb, cc = i+1, j+1, rand(3);
        instance = abc(aa, bb, cc);
        k[i][j] = instance;
    end
end

I'm getting this error:

UndefRefError: access to undefined reference

Stacktrace:

[1] getindex(::Array{Array{abc,1},1}, ::Int64) at ./array.jl:549

[2] macro expansion at ./In[7]:5 [inlined]

[3] anonymous at ./:?

Can you guys tell me what I am doing wrong? Thanks!

Upvotes: 3

Views: 1238

Answers (3)

Picaud Vincent
Picaud Vincent

Reputation: 10982

The statement:

k = Vector{Vector{abc}}(6);

only initialize the outer Vector with size 6, its components are not even vectors of zero size but simply undefined structs. For example:

julia> x=Vector{Vector{Int}}(4)

4-element Array{Array{Int64,1},1}:
 #undef
 #undef
 #undef
 #undef

You can check if a component is assigned/defined (without triggering the error you mentioned in your question) using the isassigned function:

julia> isassigned(x,2)                 // <---- here

false

julia> x[2]=Vector{Int}(3);

julia> x

4-element Array{Array{Int64,1},1}:
 #undef                                                
    [140512219699984, 140512277526048, 140512217976944]
 #undef                                                
 #undef     

julia> isassigned(x,2)                 // <---- here

true

If you know your sizes at construction time, maybe the simplest solution is to use this:

k = [Vector{abc}(5) for i in 1:6]

This will create an (outer) vector of size 6, with all its components being a Vector{abc} of size 5


update: answering your comment.

If you want to define inner vector sizes afterward I would suggest to initialize zero sized vectors then use the resize! function. Code as follows:

struct abc end # empty struct, only for demo

k=[Vector{abc}() for i in 1:6]

for i in 1:length(k)
   resize!(k[i],rand(1:6)) # here a random size
   for j in 1:length(k[i])
      # here do what you want with k[i][j]
   end
end 

Upvotes: 1

Subhankar Ghosh
Subhankar Ghosh

Reputation: 469

Try:

k = fill(Vector{abc}(),6)
for i = 1:6
   for j = 1:6
        aa, bb, cc = i+1, j+1, rand(3)
        instance = abc(aa, bb, cc)
        push!(k[i], instance)
    end
end

You need to initialize first.

Upvotes: 2

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69949

Your variable k does not have its elements initialized. You can find it when you write:

julia> k
6-element Array{Array{abc,1},1}:
 #undef
 #undef
 #undef
 #undef
 #undef
 #undef

The simplest way to fix it is to use the following pattern:

julia> k = [Vector{abc}(6) for i in 1:6]
6-element Array{Array{abc,1},1}:
 abc[#undef, #undef, #undef, #undef, #undef, #undef]
 abc[#undef, #undef, #undef, #undef, #undef, #undef]
 abc[#undef, #undef, #undef, #undef, #undef, #undef]
 abc[#undef, #undef, #undef, #undef, #undef, #undef]
 abc[#undef, #undef, #undef, #undef, #undef, #undef]
 abc[#undef, #undef, #undef, #undef, #undef, #undef]

And now all works.

Notice that in Julia 0.7/1.0 you have to write k = [Vector{abc}(undef, 6) for i in 1:6] (with undef) - exactly to indicate that you are aware that you are creating an array with undefined entries. Similarly Vector{Vector{abc}}(6) in your original code would fail and you would have to use Vector{Vector{abc}}(undef, 6) and now, I think, it is more clear that the inner arrays are not initialized.

Finally, you can do both steps in one shot using a comprehension within a comprehension like this:

[[abc(i+1, j+1, rand(3)) for j in 1:6] for i in 1:6]

Upvotes: 1

Related Questions