Initializing arrays of objects with distinct handle properties
3 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
When I initialize an array of handle objects (or matlab.mixin.Copyable) with handle properties, my properties are all handles to the same objects, except for the last element of the array. The last element makes sense based on the description of how matlab instantiates objects. The documentation here ( https://www.mathworks.com/help/matlab/matlab_oop/initialize-property-values.html ) indicates that constructors should call the constructors of any handle properties to ensure a fresh object. I do not observe this behavior.
For the classes below, Junk1 has two properties, each of type Junk2. My expectation is that prop1 would be a fresh handle because it is initialized in the Junk1 constructor, whereas prop2 has a default which is copied for all instances of Junk1 in the 'x' array except for the last element. It seems that x(1).prop1 == x(2).prop1. How can I initialize arrays of handle objects, which have handle properties that are distinct?
>> x(3,1)= Junk1();
>> x(1).prop1
ans =
Junk2 with properties:
value: -1.7115
>> x(2).prop1
ans =
Junk2 with properties:
value: -1.7115
>> x(3).prop1
ans =
Junk2 with properties:
value: 1.3703
>> x(1).prop1 == x(2).prop1
ans =
logical
1
>>
classdef Junk1 < handle
properties(GetAccess=public, SetAccess=public)
prop1 (1,1) Junk2
prop2 (1,1) Junk2 = Junk2()
end
methods(Access=public)
function obj = Junk1()
obj.prop1 = Junk2();
end
end
end
classdef Junk2 < handle
properties(GetAccess=public, SetAccess=public)
value (1,1) double
end
methods(Access=public)
function obj = Junk2(a)
if (nargin == 1)
obj.value = a;
else
obj.value = randn;
end
end
end
end
0 Kommentare
Akzeptierte Antwort
Matt J
am 22 Apr. 2023
You can also rewrite the Junk1() constructor to generate array-valued output:
classdef Junk1 < handle
properties(GetAccess=public, SetAccess=public)
prop1 (1,1) Junk2
prop2 (1,1) Junk2
end
methods(Access=public)
function obj = Junk1(varargin)
if ~nargin, return; end
siz=[varargin{:}];
obj(prod(siz))=Junk1();
obj=reshape(obj,siz);
for i=1:numel(obj)
obj(i).prop1=Junk2();
end
end
end
end
>> x=Junk1(3,1), x.prop1
x =
3×1 Junk1 array with properties:
prop1
prop2
ans =
Junk2 with properties:
value: 0.1339
ans =
Junk2 with properties:
value: 0.6561
ans =
Junk2 with properties:
value: 0.6697
2 Kommentare
Matt J
am 25 Apr. 2023
Bearbeitet: Matt J
am 25 Apr. 2023
The matlab documentation is accurate in that calling property constructors in the main constructor does result in distinct object handles for repeated calls, just not for array creation.
Yes... but I think it's important to understand that that's only because there are no repeated constructor calls when you create an array of default elements. A default element is created by calling the constructor once, and that object is then copied throughout the array where needed. This is true for all object types, both handle and value, and for both user-defined and built-in objects. The following code modification shows that the constructor is called twice, even though 10 elements are created. You can verify that this happens for value objects as well.
classdef Junk1 < handle
properties(GetAccess=public, SetAccess=public)
prop1 (1,1) Junk2
end
methods
function obj=Junk1()
disp 'Constructing'
obj.prop1=Junk2();
end
end
methods(Static)
function objs = array(varargin)
objs=arrayfun(@(z)Junk1(), ones(varargin{:}) );
end
end
end
>> x(10)=Junk1
Constructing
Constructing
x =
10×1 Junk1 array with properties:
prop1
Weitere Antworten (1)
Matt J
am 22 Apr. 2023
Bearbeitet: Matt J
am 22 Apr. 2023
One way:
x=arrayfun(@(z)Junk1,ones(3,1))
x.prop1
x =
3×1 Junk1 array with properties:
prop1
prop2
ans =
Junk2 with properties:
value: -0.7108
ans =
Junk2 with properties:
value: 0.3310
ans =
Junk2 with properties:
value: 0.3542
5 Kommentare
Matt J
am 24 Apr. 2023
Bearbeitet: Matt J
am 25 Apr. 2023
By explicitly calling the constructor of any handle class properties in the main class constructor, I expected all the elements to get distinct properties.
If a separate constructor call were made to fill every unspecified array element, that would be very slow. That's not how any of the Matlab classes work, even the built-in ones. Consider the example below. Does it surprise you that the first 4 elements of x are copies of the same element (0) ?
x(5,1)=double(1)
Matt J
am 24 Apr. 2023
Rewriting the constructor below is an option, but many of my classes have either an N argument signature for providing content or a 0 argument signature for array initialization.
If you don't want to redesign your constructor syntax for the purpose of creating object arrays, you can always add a Static method for this purpose, e.g.,
classdef Junk1 < handle
properties(GetAccess=public, SetAccess=public)
prop1 (1,1) Junk2
end
methods
function obj=Junk1()
obj.prop1=Junk2();
end
end
methods(Static)
function objs = array(varargin)
objs=arrayfun(@(z)Junk1(), ones(varargin{:}) );
end
end
end
>> x=Junk1.array(3,1), x.prop1
x =
3×1 Junk1 array with properties:
prop1
ans =
Junk2 with properties:
value: -0.7601
ans =
Junk2 with properties:
value: 1.2245
ans =
Junk2 with properties:
value: 1.4168
Siehe auch
Kategorien
Mehr zu Handle Classes finden Sie in Help Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!