Lemma is an Electromagnetics API
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mem.dox 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. namespace Lemma{
  2. /**
  3. \page Memory
  4. <div class="lemmamainmenu">
  5. \ref Intro "Intro"
  6. | \ref Compiling "Compiling"
  7. | \b Memory \b management
  8. | \ref Minimal "Minimal programme"
  9. | \ref EmSources "EM Sources"
  10. </div>
  11. \section MemoryManagement Memory Management
  12. \subsection Reference Reference counting and memory management
  13. \note Previous versions of Lemma used an internal reference counting mechanism, what
  14. is described below represents a significant change in the structure, philosophy,
  15. and internals of Lemma. To a large extent this has been possible due to changes
  16. in the C++ language specifications since C++-0x. These changes should improve the
  17. readability of Lemma code, decrease errors, improve performance, and reduce code length.
  18. The C++-17 standard promises to close a remaining oddities in the Lemma API, discussed below.
  19. Lemma relies heavily on smart pointer which utilize internal reference counting for several reasons:
  20. - It is not uncommon for multiple objects to have the same instantiations of an object as members.
  21. - Making copies of each object is not a viable option because the objects may be large, and they must all update simultaneously.
  22. - Without reference counting it is very easy to leave dangling pointers.
  23. - It is much easier to write code, as local copies of objects can be deleted
  24. as soon as they are no longer used within that context. The memory will not be
  25. freed and the object persists as long as other objects still reference it.
  26. The C++-0x standard introduced std::shared_ptr as a widely available, standard-compliant, high performance option to use
  27. in instances like this. The other smart pointer types specifically weak_ptr and unique_ptr are less handy in our application. As such,
  28. all Lemma classes expose a factory method returning a shared_ptr as the only publicly available means by which to construct objects.
  29. Internally, in cases where higher performance can be realized, manual memory management is employed.
  30. The base class for all Lemma objects is LemmaObject.
  31. The interface requires that all derived, non-abstract classes have <B>NewSP</B> and <B>DeSerialize</B> methods. These methods are the only
  32. mechanisms by which you should be creating Lemma objects.
  33. \code
  34. std::shared_ptr< DerivedClass > Object = DerivedClass::NewSP();
  35. // Or alternatively
  36. auto Object2 = DerivedClass::NewSP();
  37. \endcode
  38. \warning It is important to note that the default constructors and destructors are inaccessible so the following code is <B>NOT</B> valid.
  39. \code
  40. DerivedClass* Object = new DerivedClass;
  41. delete Object;
  42. \endcode
  43. Interestingly, the default constructors and destructors <B>are</B> public, however they are locked using a key struct
  44. <a href=http://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const/8147326#8147326> (link)</a>.
  45. The reason that this is necessary, is this arrangement allows for the use of std::make_shared to construct objects. The performance increase of this was
  46. chosen over the higher overhead associated with making the default methods protected.
  47. Many Lemma classes have other Lemma classes as data members. Classes may
  48. share these members, and depend on them being updated simultaneously. So
  49. that a situation like this is not unusual.
  50. \code
  51. DerivedClass* Component = DerivedClass::New();
  52. AnotherDerivedClass* Object2 = AnotherDerivedClass::New();
  53. YetAnotherDerivedClass* Object3 = YetAnotherDerivedClass::New();
  54. Object2->AttachMyComponent(Component);
  55. Object3->AttachMyComponent(Component);
  56. Component->Update(); // All three classes use the updated Component
  57. \endcode
  58. At this point both Object2 and Object3 have an up to date Component and any
  59. changes to Component can be seen by the Objects. Often these types of
  60. connections are happening behind the scenes and end users should not be
  61. troubled by any of this.
  62. Now in this example it is clear that if Component is deleted, than the objects
  63. will contain dangling pointers. To avert this, calling the
  64. ReferenceCountedObject::Delete() does not necessarily destroy the object.
  65. So that it would be safe -- continuing from the above example
  66. \code
  67. Component->Delete(); // The 'Component' handle will no longer be used.
  68. Object2->CallMethodRelyingOnComponent(); // But we can still use the object
  69. \endcode
  70. \subsection what Whats going on?
  71. Whenever we declared a new handle to the object-- either by calling New, or implicitly in the Connect methods--
  72. the true 'Component' object updated a list of pointers that had handles to it.
  73. \code
  74. DerivedClass* Component = DerivedClass::New(); // One Reference, 'Component'
  75. Object2->AttachMyComponent(Component); // Two References, internal in Object2
  76. Object3->AttachMyComponent(Component); // Three References, internal in Object3
  77. Component->Delete(); // Two References, 'Component' is gone.
  78. // DON'T USE Component->Method() ANYMORE!!!
  79. Object2->Delete(); // One Reference, Object2 releases handle upon Delete
  80. Object3->SomeFuntionReleasingComponent(); // Zero References, Component object is now deleted and
  81. // all memory is freed!
  82. \endcode
  83. \section So So what do I need to know?
  84. Not much. This is here to make life easy when doing high level programming. Just follow these simple rules
  85. - Allocate and free all variables with New and Delete, you have to do this as the default
  86. versions are protected.
  87. - Once calling Delete on an object it is no longer safe to use that handle. For example don't call
  88. Component->Delete(), and then call Component->Method(). Even if you 'know' that there are existing references
  89. and that it shouldn't have been deleted yet. Instead move your call to Delete down after your last direct use
  90. of each class.
  91. - Remember to call Delete, thanks to reference counting it is safe to do this as soon as you are done
  92. using an object even if other classes are using it. If you don't call Delete on objects you create, your
  93. program <B>will</B> leak memory!
  94. - Revel in the fact that memory is being managed for you, and that dangling pointers are not a concern.
  95. */
  96. }