Difficulty: Medium · Puzzle 4 of 6 · Topic: Queue and Array Puzzles
Predict the output. Why does changing `da[0].v` also change `db[0].v` after the resize-copy, but replacing `da[1]` does not change `db[1]`?
class item;
int v;
function new(int v); this.v = v; endfunction
endclass
module p4;
item da[];
item db[];
item dc[];
initial begin
da = new[2];
da[0] = new(10);
da[1] = new(20);
db = new[3](da);
db[2] = new(30);
da[0].v = 99;
da[1] = new(55);
$display("da0=%0d db0=%0d da1=%0d db1=%0d db2=%0d",
da[0].v, db[0].v, da[1].v, db[1].v, db[2].v);
dc = new[da.size()];
foreach (da[i]) dc[i] = new(da[i].v);
da[0].v = 1;
$display("dc0=%0d da0=%0d", dc[0].v, da[0].v);
end
endmodule`new[N](old)` copies the elements, but when the element type is a class handle the copied value is the handle. Ask separately: did I change the object, or did I change which object the array element points to?
1) `db = new[3](da)` copies the two handles, so db[0] and da[0] reference the same object (v=10), as do db[1] and da[1] (v=20).
2) `da[0].v = 99` modifies that shared object, so db[0].v is 99 too.
3) `da[1] = new(55)` overwrites only da's slot with a handle to a new object; db[1] still points to the old object with v=20.
4) db[2] was constructed separately and stays 30.
5) The `foreach` loop constructs new objects, so dc is a deep copy: changing `da[0].v` to 1 leaves dc[0].v at 99.Answer: da0=99 db0=99 da1=55 db1=20 db2=30, then dc0=99 da0=1
Checked by running the code in Verilator 5; the printed output supports the answer above. Copied handles share the object, re-assigned slots do not; Icarus 13 cannot compile arrays of class handles.
Mutating the shared object shows through both arrays, but re-assigning an element only changes one array; candidates who say 'the arrays are linked' get da1/db1 wrong.
What code pattern gives deep-copy semantics for arrays of class handles? Model answer: construct a new object per element, as in the `foreach (da[i]) dc[i] = new(da[i].v);` loop above, or give the class a `copy()`/`clone()` method that returns a new object and call it per element (the copy must also recurse into any handle fields).
I would track which slots hold handles to the same object, because the resize copies handles and not objects. So changing the field through the first array shows in the second, giving 99 in both. But assigning a new object into one slot of the first array does not touch the second, so da1 is 55 and db1 is still 20, and db2 is 30. The loop that constructs new objects is a deep copy, so changing da0 to 1 later leaves dc0 at 99. The trap is thinking the arrays are linked, and I would check any copy for shared objects.