ReferenceContainers
The ReferenceContainer is one of the core classes of the framework and allows to create trees of references of any complexity.

Given that the ReferenceContainer inherits from Object, all the strategies described in the References section also apply.
//This is a valid way of creating a new ReferenceContainer
ReferenceT<ReferenceContainer> ref("ReferenceContainer", GlobalObjectsDatabase::Instance()->GetStandardHeap());
Note
The access to the container is protected by an internal FastPollingMutexSem whose timeout can be specified.
The ReferenceContainer Purge method must be called when the object is no longer needed (typically when the application terminates).
The Purge function will destroy each element of the container and break any reference loops (the father contains a reference to the children and the children contains a reference to the father).
This method must also be used to implement any house-cleaning that is required before the elements are removed from the container (e.g. stopping threads that use these Objects). An example can be found in the Purge method of the StateMachine class.
Warning
The smart pointer mechanism guarantees that when there are no references pointing at a given object, this object is destroyed. Nevertheless, this does not prevent developers from creating internal references, so that there will be at least one reference pointing at the Object and thus it never gets destroyed.
An example:
A is a specialised ReferenceContainer and has a member b which is also a ReferenceContainer.
b contains an element C (b.Get(0)) which in turn contains a reference to A.
A will then always have at least one unreachable reference pointing at it, as b can only be destroyed (thus calling Delete(0)) when A is destroyed, but A cannot be destroyed because it has a reference pointing at it.

This can be handled by specialing the Object Purge method (see the Example below).
Nevertheless, avoid designs where classes have ReferenceContainer members. If you have to have such variables in your class, make sure that the Purge method is specialised to manually break any link (see ReferenceContainer), as otherwise unattended circular references may prevent the underlying Objects from being destroyed.
The preferred strategy is to have the class directly inheriting from ReferenceContainer and to add any references to it. Note also that the ReferenceContainer may hold, contemporarily, references to any number of class types.
Examples
The following example shows how to add/get references to/from a container.
1/**
2 * @file ReferencesExample5.cpp
3 * @brief Source file for class ReferencesExample5
4 * @date 14/03/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class ReferencesExample5 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "ClassRegistryDatabase.h"
35#include "ErrorLoggerExample.h"
36#include "Object.h"
37#include "Reference.h"
38#include "ReferenceContainer.h"
39#include "ReferenceT.h"
40#include "StreamString.h"
41
42/*---------------------------------------------------------------------------*/
43/* Static definitions */
44/*---------------------------------------------------------------------------*/
45
46/*---------------------------------------------------------------------------*/
47/* Method definitions */
48/*---------------------------------------------------------------------------*/
49namespace MARTe2Tutorial {
50
51
52class ControllerEx1: public MARTe::Object {
53public:
54 CLASS_REGISTER_DECLARATION()
55
56 /**
57 * @brief NOOP.
58 */
59ControllerEx1 () {
60 gain = 0u;
61 }
62
63 virtual ~ControllerEx1() {
64 using namespace MARTe;
65 if (GetName() != NULL) {
66 REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
67 "pointing at %s [%s]. The Object will "
68 "be safely deleted.", GetName(), GetClassProperties()->GetName());
69 }
70 }
71
72 virtual void AFunction () {
73 using namespace MARTe;
74 REPORT_ERROR_STATIC(ErrorManagement::Information, "AFunction called @ %s.", GetName());
75 }
76
77 /**
78 * A property.
79 */
80 MARTe::uint32 gain;
81};
82
83CLASS_REGISTER(ControllerEx1, "")
84
85class PIDEx1: public ControllerEx1 {
86public:
87 CLASS_REGISTER_DECLARATION()
88
89 /**
90 * @brief NOOP.
91 */
92PIDEx1 () {
93 property3 = 0u;
94 }
95
96 virtual ~PIDEx1() {
97 using namespace MARTe;
98 REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
99 "pointing at %s [%s]. The Object will "
100 "be safely deleted.", GetName(), GetClassProperties()->GetName());
101 }
102
103 virtual void AFunction () {
104 using namespace MARTe;
105 REPORT_ERROR_STATIC(ErrorManagement::Information, "AFunction called @ %s.", GetName());
106 }
107 /**
108 * A property.
109 */
110 MARTe::uint32 property3;
111};
112
113CLASS_REGISTER(PIDEx1, "")
114
115
116class ControllerContainerEx1: public MARTe::ReferenceContainer {
117public:
118 CLASS_REGISTER_DECLARATION()
119
120 /**
121 * @brief NOOP.
122 */
123 ControllerContainerEx1() {
124 }
125
126 virtual ~ControllerContainerEx1() {
127 using namespace MARTe;
128 REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
129 "pointing at %s [%s]. The Object will "
130 "be safely deleted.", GetName(), GetClassProperties()->GetName());
131 }
132
133 /**
134 * @brief Calls AFunction on all of its elements
135 */
136 void Do() {
137 using namespace MARTe;
138 uint32 i;
139 uint32 size = Size();
140 for (i = 0u; i < size; i++) {
141 ReferenceT<ControllerEx1> r = Get(i);
142 if (r.IsValid()) {
143 r->AFunction();
144 }
145 }
146 }
147
148};
149CLASS_REGISTER(ControllerContainerEx1, "")
150
151}
152
153int main(int argc, char **argv) {
154 using namespace MARTe;
155 using namespace MARTe2Tutorial;
156 SetErrorProcessFunction(&ErrorProcessExampleFunction);
157
158 CCString className1 = "ControllerEx1";
159 CCString className2 = "PIDEx1";
160
161 //Automatically generate a new object instance based on the class
162 //name and on the correct Heap and with the template reference.
163 ReferenceT<ControllerEx1> ref1(className1,
164 GlobalObjectsDatabase::Instance()->GetStandardHeap());
165 if (ref1.IsValid()) {
166 ref1->SetName("ControllerInstance1");
167 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully "
168 "created an instance of %s", className1.GetList());
169 }
170 ReferenceT<ControllerEx1> ref2(className2,
171 GlobalObjectsDatabase::Instance()->GetStandardHeap());
172 if (ref2.IsValid()) {
173 ref2->SetName("ControllerInstance2");
174 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully "
175 "created an instance of %s", className2.GetList());
176 }
177 //This mechanism also works with compatible subclasses PIDEx1->ControllerEx1
178 ReferenceT<PIDEx1> ref3(className2,
179 GlobalObjectsDatabase::Instance()->GetStandardHeap());
180 if (ref3.IsValid()) {
181 ref3->SetName("PIDInstance1");
182 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully "
183 "created an instance of %s", className2.GetList());
184 }
185
186 ReferenceT<ControllerContainerEx1> controllerContainer("ControllerContainerEx1",
187 GlobalObjectsDatabase::Instance()->GetStandardHeap());
188 if (controllerContainer.IsValid()) {
189 controllerContainer->SetName("Container");
190 controllerContainer->Insert(ref1);
191 controllerContainer->Insert(ref2);
192 controllerContainer->Insert(ref3);
193 controllerContainer->Do();
194 }
195 return 0;
196}
This example highlights the circular reference problem. By specialising the Purge method, the ContainerEx2 class will break the link and allow all Objects to be destroyed.
1/**
2 * @file ReferencesExample6.cpp
3 * @brief Source file for class ReferencesExample6
4 * @date 14/03/2018
5 * @author Andre' Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class ReferencesExample6 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24#define DLL_API
25
26/*---------------------------------------------------------------------------*/
27/* Standard header includes */
28/*---------------------------------------------------------------------------*/
29
30/*---------------------------------------------------------------------------*/
31/* Project header includes */
32/*---------------------------------------------------------------------------*/
33#include "AdvancedErrorManagement.h"
34#include "ClassRegistryDatabase.h"
35#include "ErrorLoggerExample.h"
36#include "Object.h"
37#include "ObjectRegistryDatabase.h"
38#include "Reference.h"
39#include "ReferenceContainer.h"
40#include "ReferenceT.h"
41#include "StreamString.h"
42
43/*---------------------------------------------------------------------------*/
44/* Static definitions */
45/*---------------------------------------------------------------------------*/
46
47/*---------------------------------------------------------------------------*/
48/* Method definitions */
49/*---------------------------------------------------------------------------*/
50namespace MARTe2Tutorial {
51
52class ObjectEx1: public MARTe::Object {
53public:
54 CLASS_REGISTER_DECLARATION()
55
56 /**
57 * @brief NOOP.
58 */
59 ObjectEx1 () {
60 }
61
62 virtual ~ObjectEx1() {
63 using namespace MARTe;
64 if (GetName() != NULL) {
65 REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
66 "pointing at %s [%s]. The Object will "
67 "be safely deleted.", GetName(), GetClassProperties()->GetName());
68 }
69 }
70
71 void SetParent(MARTe::Reference ref) {
72 parent = ref;
73 }
74
75 /**
76 * A private container. This should be avoided!
77 */
78 MARTe::Reference parent;
79
80};
81
82CLASS_REGISTER(ObjectEx1, "")
83
84/**
85 * Does not implement the Purge method and as such a cyclic link will not be broken.
86 */
87class ContainerEx1: public MARTe::ReferenceContainer {
88public:
89 CLASS_REGISTER_DECLARATION()
90
91 /**
92 * @brief NOOP.
93 */
94 ContainerEx1 () {
95 }
96
97 virtual ~ContainerEx1() {
98 using namespace MARTe;
99 REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
100 "pointing at %s [%s]. The Object will "
101 "be safely deleted.", GetName(), GetClassProperties()->GetName());
102 }
103
104 void CreateLoop(MARTe::Reference aReferenceIn) {
105 aReference.Insert(aReferenceIn);
106 }
107
108 MARTe::ReferenceContainer aReference;
109};
110CLASS_REGISTER(ContainerEx1, "")
111
112/**
113 * Implements the Purge method.
114 */
115class ContainerEx2: public ContainerEx1 {
116public:
117 CLASS_REGISTER_DECLARATION()
118
119 /**
120 * @brief NOOP.
121 */
122 ContainerEx2 () {
123 }
124
125 virtual ~ContainerEx2() {
126 using namespace MARTe;
127 REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
128 "pointing at %s [%s]. The Object will "
129 "be safely deleted.", GetName(), GetClassProperties()->GetName());
130 }
131
132 /**
133 * Destroys an existent links
134 */
135 virtual void Purge(MARTe::ReferenceContainer &purgeList) {
136 using namespace MARTe;
137 //Destroy the circular link
138 aReference.Purge();
139 //Alternative which would also destroy the link
140 /*ReferenceT<ObjectEx1> ref = aReference.Get(0);
141 if (ref.IsValid()) {
142 //Set an invalid reference to break the link.
143 ref->SetParent(Reference());
144 }*/
145 //Do not forget to call the parent implementation
146 ReferenceContainer::Purge(purgeList);
147 }
148
149};
150CLASS_REGISTER(ContainerEx2, "")
151
152}
153
154int main(int argc, char **argv) {
155 using namespace MARTe;
156 using namespace MARTe2Tutorial;
157 SetErrorProcessFunction(&ErrorProcessExampleFunction);
158
159 CCString className1 = "ObjectEx1";
160 CCString className2 = "ContainerEx1";
161 CCString className3 = "ContainerEx2";
162
163 //Automatically generate a new object instance based on the class
164 //name and on the correct Heap and with the template reference.
165 ReferenceT<ObjectEx1> ref1(className1,
166 GlobalObjectsDatabase::Instance()->GetStandardHeap());
167 if (ref1.IsValid()) {
168 ref1->SetName("ObjectExIntance1");
169 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully "
170 "created an instance of %s", className1.GetList());
171 }
172 ReferenceT<ObjectEx1> ref2(className1,
173 GlobalObjectsDatabase::Instance()->GetStandardHeap());
174 if (ref2.IsValid()) {
175 ref2->SetName("ObjectExIntance2");
176 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully "
177 "created an instance of %s", className1.GetList());
178 }
179 ReferenceT<ContainerEx1> ref3(className2,
180 GlobalObjectsDatabase::Instance()->GetStandardHeap());
181 if (ref3.IsValid()) {
182 ref3->SetName("ContainerExIntance1");
183 ref3->Insert(ref1);
184 //This will create a circular dependency
185 ref3->CreateLoop(ref1);
186 ref1->SetParent(ref3);
187 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully "
188 "created an instance of %s", className2.GetList());
189
190 }
191 ReferenceT<ContainerEx2> ref4(className3,
192 GlobalObjectsDatabase::Instance()->GetStandardHeap());
193 if (ref4.IsValid()) {
194 ref4->SetName("ContainerExIntance2");
195 ref4->Insert(ref2);
196 ref4->CreateLoop(ref2);
197 ref2->SetParent(ref4);
198 REPORT_ERROR_STATIC(ErrorManagement::Information, "Successfully "
199 "created an instance of %s", className3.GetList());
200 }
201
202 if (ref3.IsValid()) {
203 ref3->Purge();
204 }
205 if (ref4.IsValid()) {
206 ref4->ReferenceContainer::Purge();
207 }
208
209 if (ref1.IsValid() && ref2.IsValid() && ref3.IsValid() && ref4.IsValid()) {
210 REPORT_ERROR_STATIC(ErrorManagement::Information, "%s "
211 "number of references: %d", ref1->GetName(),
212 ref3->NumberOfReferences());
213 REPORT_ERROR_STATIC(ErrorManagement::Information, "%s "
214 "number of references: %d", ref2->GetName(),
215 ref2->NumberOfReferences());
216 REPORT_ERROR_STATIC(ErrorManagement::Information, "%s "
217 "number of references: %d", ref3->GetName(),
218 ref3->NumberOfReferences());
219 REPORT_ERROR_STATIC(ErrorManagement::Information, "%s "
220 "number of references: %d", ref4->GetName(),
221 ref4->NumberOfReferences());
222
223 if (ref1->NumberOfReferences() == 2u
224 && ref3->NumberOfReferences() == 2u) {
225 REPORT_ERROR_STATIC(ErrorManagement::Warning,
226 "As expected %s and %s have a circular dependency and thus cannot be destroyed."
227 , ref1->GetName(), ref3->GetName());
228 }
229 }
230 return 0;
231}