implementation.user - moduleus/urx GitHub Wiki
Les opérateurs ==
et !=
sont implémentés pour toutes les classes UAC/URX.
If a class can be using inside a weak_ptr
or shared_ptr
, you need to add header urx/detail/compare.h
. This header overrides comparison for smart pointers. You will make a deep comparison and not a pointer value comparison.
Si vous souhaitez forcer la comparaison des pointeurs, il faut le faire de façon explicite:
- Shared pointer
std::shared_ptr<...> data;
data.get() == ...
- Weak pointer
std::weak_ptr<...> data;
if (data.expired()) {
// A considérer comme non assigné ou comme expiré
} else {
data.lock().get();
}
Si vous voulez utiliser la comparaison des handle MATLAB, utilisez l'opérateur ==
et ~=
.
Si vous effectuer une comparaison en profondeur, utilisez la fonction isequaln
. Il est aussi possible d'utiliser la fonction isequal
mais son comportement est identique à isequaln
.
- Raw
Transform transform;
Si transform
est une variable dans le corps d'une fonction, la mémoire est allouée dans la pile et sera libérée à la fermeture du bloc ({...}
).
Si la variable est un membre d'une structure, elle sera allouée en même temps que la structure et a la même durée de vie que la structure.
- Shared pointer
std::shared_ptr<urx::Dataset> dataset = std::make_shared<urx::Dataset>();
La mémoire est allouée dans le tas. Elle sera libérée lorsque tous les std::shared_ptr seront détruits.
La syntaxe std::shared_ptr<urx::Dataset> dataset;
déclare un shared pointer qui contient un pointeur null. Il est impératif d'appeler le constructeur avec la méthode std::make_shared
.
- Weak pointer
std::shared_ptr<urx::ElementGeometry> element_geometry = std::make_shared<urx::ElementGeometry>();
std::weak_ptr<urx::ElementGeometry> element_geometry_weak = element_geometry;
Il s'agit d'un pointeur vers la mémoire allouée dans un shared pointer. Si tous les objets shared pointer sont détruits, le pointeur stocké dans l'objet weak pointer deviendra invalide.
- Optional
std::optional<TriggerIn> trigger_in = uac::TriggerIn;
Si trigger_in est une variable dans le corps d'une fonction, la mémoire est allouée dans la pile et sera libérée à la fermeture du bloc ({...}
).
Si la variable est un membre d'une structure, elle sera alloué en même temps que la structure.
La différence avec un objet de type Raw, c'est que, même si la mémoire est allouée, l'objet n'est pas construit tant que le constructeur n'a pas été appelé explicitement. Ainsi, std::optional<TriggerIn> trigger_in
déclare une variable trigger_in
qui vaut std::nullopt
.
Toutes les données sont stockées dans un objet racine : dataset.
Cet objet doit être alloué par :
- en C++ : auto dataset = std::make_shared<urx::Dataset>();
- en MATLAB : dataset = urx.Dataset();
- en Python : dataset = urx.Dataset();
Quelque soit l'implémentation utilisée (C++, MATLAB ou Python), toutes respectent l'implémentation en C++. Ainsi, si le champ d'une structure en C++ est déclarée en weak pointer, elle se comportera de la même façon en MATLAB et Python.
Tous les membres qui sont déclarés en weak pointer doivent pointer vers un shared pointer préalablement stocké dans son champ dédié (voir la description de chaque champ weak pointer pour connaitre le champ shared pointer dédié).
Toutes les données allouées par MATLAB sont forcément des shared pointers.
Cependant, lorsque vous assignez un objet UAC/URX dans un membre d'un autre objet UAC/URX, les deux éléments peuvent être du même type mais ne pas avoir la même allocation mémoire.
dataset = urx.Dataset();
version = urx.Version();
version.minor = 1;
version.major = 2;
version.patch = 3;
dataset.version = version;
dataset
et version
sont des shared pointer et dataset.version
est un raw pointer.
A la ligne dataset.version = version
, les données de version
sont copiées dans le membre version
de dataset
.
Chaque objet UAC/URX ayant un handle, et afin de garder une cohérence des données, la variable version
sera automatiquement modifiée et converti en raw pointer et pointera vers dataset.version
.
element=urx.Element;
elementGeometry=urx.ElementGeometry;
element.elementGeometry = elementGeometry;
element
et elementGeometry
sont des shared pointer et element.elementGeometry
est un weak pointer.
A la ligne element.elementGeometry = elementGeometry
, le shared pointer elementGeometry
est assigné au champ elementGeometry
de element
.
Comme tous les deux sont des pointeurs, la variable elementGeometry
reste un shared pointer n'est pas converti en weak pointer. En effet, si le shared pointer était converti en weak pointer, la mémoire serait libérée car plus aucun objet de type shared pointer ne stockerait l'allocation mémoire de l'élément géometrie.
Cependant, il reste important de stocker la variable elementGeometry dans le champ elementGeometries de sa sonde et que sa sonde soit stocké dans le dataset global.
probe = urx.Probe;
probe.elementGeometries = elementGeometry;
dataset = urx.Dataset;
dataset.probes = probe;
Urx MATLAB classes don't hold any value. They are read in real time from the C++ back-end. So there is some limitations with C++ vectors.
acquisition = urx.Acquisition();
groupData = urx.GroupData();
acquisition.groupsData = [groupData, groupData];
At first, groupData
is a shared object because it's allocated by MATLAB.
By design, acquisition.groupsData
holds only raw objects. groupData
is copied to every index in acquisition.groupsData
.
After the assignment, groupData
is a raw object and points to the last index where it's used in acquisition.groupsData
.
In C++, when you change the size of a vector, it may realloc memory and user can't manage it.
acquisition = urx.Acquisition();
groupData1 = urx.GroupData();
acquisition.groupsData = [groupData1];
groupDataRawRef = acquisition.groupsData;
groupData2 = urx.GroupData();
acquisition.groupsData = [groupData2, groupData2];
At first, groupData1
is a shared object. After its insertion in acquisition.groupsData
, groupData1
is converted to a raw object.
groupDataRawRef
is a raw object that point to the same data than groupData1
.
When acquisition.groupsData
is reassign with a new size, the C++ vector need to do a re-allocation in memory.
At this moment, groupDataRawRef
points to an invalid data. Using this object with throw an exception with message: Failed to get property XXXX. Object doesn't belong to urx.Acquisition.groupsData anymore. The vector has changed or the C++ vector has reallocated memory and the object has became invalid.
.
Pybind11 handles pointers as shared_ptr
by default.
Python doesn't support weak_ptr
. The default behavior for getting a weak_ptr
is the same as getting a shared_ptr
except that a runtime_error
exception is raised if the pointer has expired.
Each GroupData
have data in field raw_data
.
It's the only field that have complex class: RawData
. It's an interface with 4 getters : getBuffer
, getSize
, getSamplingType
and getDataType
. getBuffer
returns a void*
pointer that is not const. But once the RawData class is allocated, you can't grow or shrink it, only modify it.
RawData may be allocated come from multiple source, you can have:
-
RawDataVector
to have astd::vector
as buffer. When youresize()
, all value are initialized by 0. -
RawDataNoInit
an array that don't initialize data. -
RawDataWeak
to store a pointer without managing life cycling. It doesn't store astd::weak_ptr
, only a pointer.