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