Library: better let C++ handle the destructors
...what I've implemented yesterday is effectively the same functionality as provided automatically by the C++ object system when using a virtual destructor. Thus a much cleaner solution is to turn `Destructor` into a interface and let C++ do all the hard work. Verified in test: works as intended
This commit is contained in:
parent
71d5851701
commit
be398e950a
5 changed files with 124 additions and 165 deletions
|
|
@ -100,7 +100,7 @@ namespace lib {
|
|||
* An _overlay view_ for the AllocationCluster to add functionality
|
||||
* for adding / clearing extents and registering optional deleter functions.
|
||||
* @warning this is a tricky construct to operate each Allocation Cluster
|
||||
* with the absolute necessary minimum of organisational overhead.
|
||||
* with the absolute minimum of organisational overhead necessary.
|
||||
* The key point to note is that StorageManager is layout compatible
|
||||
* with AllocationCluster itself — achieved through use of the union
|
||||
* ManagementView, which holds a Storage descriptor member, but
|
||||
|
|
@ -112,19 +112,10 @@ namespace lib {
|
|||
*/
|
||||
class AllocationCluster::StorageManager
|
||||
{
|
||||
struct Destructor
|
||||
{
|
||||
Destructor* next;
|
||||
DtorInvoker dtor;
|
||||
|
||||
~Destructor()
|
||||
{
|
||||
if (dtor)
|
||||
(*dtor) (this);
|
||||
}
|
||||
};
|
||||
|
||||
using Destructors = lib::LinkedElements<Destructor, PolicyInvokeDtor>;
|
||||
|
||||
/** Block of allocated storage */
|
||||
struct Extent
|
||||
: util::NonCopyable
|
||||
{
|
||||
|
|
@ -142,7 +133,7 @@ namespace lib {
|
|||
|
||||
ManagementView view_;
|
||||
|
||||
StorageManager() = delete; ///< @warning used as _overlay view_ only, never created
|
||||
StorageManager() = delete; ///< @note used as _overlay view_ only, never created
|
||||
|
||||
public:
|
||||
static StorageManager&
|
||||
|
|
@ -166,16 +157,9 @@ namespace lib {
|
|||
}
|
||||
|
||||
void
|
||||
addDestructor (void* dtor)
|
||||
attach (Destructor& dtor)
|
||||
{
|
||||
auto& destructor = * static_cast<Destructor*> (dtor);
|
||||
getCurrentBlockStart()->dtors.push (destructor);
|
||||
}
|
||||
|
||||
void
|
||||
discardLastDestructor()
|
||||
{
|
||||
getCurrentBlockStart()->dtors.pop();
|
||||
getCurrentBlockStart()->dtors.push (dtor);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -195,6 +179,7 @@ namespace lib {
|
|||
|
||||
static auto determineStorageSize (AllocationCluster const&);
|
||||
|
||||
|
||||
private:
|
||||
Extent*
|
||||
getCurrentBlockStart() const
|
||||
|
|
@ -240,7 +225,7 @@ namespace lib {
|
|||
|
||||
|
||||
/**
|
||||
* On shutdown of the AllocationCluster walks all extents and invokes all
|
||||
* The shutdown of an AllocationCluster walks all extents and invokes all
|
||||
* registered deleter functions and then discards the complete storage.
|
||||
* @note it is possible to allocate objects as _disposable_ — meaning
|
||||
* that no destructors will be enrolled and called for such objects.
|
||||
|
|
@ -254,6 +239,11 @@ namespace lib {
|
|||
ERROR_LOG_AND_IGNORE (progress, "discarding AllocationCluster")
|
||||
|
||||
|
||||
/** virtual dtor to cause invocation of the payload's dtor on clean-up */
|
||||
AllocationCluster::Destructor::~Destructor() { };
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Expand the alloted storage pool by a block,
|
||||
* suitable to accommodate at least the indicated request.
|
||||
|
|
@ -269,16 +259,9 @@ namespace lib {
|
|||
|
||||
|
||||
void
|
||||
AllocationCluster::registerDestructor (void* dtor)
|
||||
AllocationCluster::registerDestructor (Destructor& dtor)
|
||||
{
|
||||
StorageManager::access(*this).addDestructor (dtor);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AllocationCluster::discardLastDestructor()
|
||||
{
|
||||
StorageManager::access(*this).discardLastDestructor();
|
||||
StorageManager::access(*this).attach (dtor);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
** Memory management for the low-level model (render nodes network).
|
||||
** The model is organised into temporal segments, which are considered
|
||||
** to be structurally constant and uniform. The objects within each
|
||||
** segment are strongly interconnected, and thus each segment is
|
||||
** being built in a single build process and is replaced or released
|
||||
** segment are strongly interconnected, and thus each segment is
|
||||
** created within a single build process and is replaced or released
|
||||
** as a whole. AllocationCluster implements memory management to
|
||||
** support this usage pattern.
|
||||
**
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
**
|
||||
** @see allocation-cluster-test.cpp
|
||||
** @see builder::ToolFactory
|
||||
** @see frameid.hpp
|
||||
** @see linked-elements.hpp
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -55,32 +55,17 @@ namespace lib {
|
|||
namespace test { class AllocationCluster_test; } // declared friend for low-level-checks
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* A pile of objects sharing common allocation and lifecycle.
|
||||
* AllocationCluster owns a number of object families of various types.
|
||||
* Each of those contains a initially undetermined (but rather large)
|
||||
* number of individual objects, which can be expected to be allocated
|
||||
* within a short timespan and which are to be released cleanly on
|
||||
* destruction of the AllocationCluster. We provide a service creating
|
||||
* individual objects with arbitrary ctor parameters.
|
||||
* @warning make sure the objects dtors aren't called and object references
|
||||
* aren't used after shutting down a given AllocationCluster.
|
||||
* @todo implement a facility to control the oder in which
|
||||
* the object families are to be discarded. Currently
|
||||
* they are just purged in reverse order defined by
|
||||
* the first request for allocating a certain type.
|
||||
* @todo should we use an per-instance lock? We can't avoid
|
||||
* the class-wide lock, unless also the type-ID registration
|
||||
* is done on a per-instance base. AllocationCluster is intended
|
||||
* to be used within the builder, which executes in a dedicated
|
||||
* thread. Thus I doubt lock contention could be a problem and
|
||||
* we can avoid using a mutex per instance. Re-evaluate this!
|
||||
* @todo currently all AllocationCluster instances share the same type-IDs.
|
||||
* When used within different usage contexts this leads to some slots
|
||||
* remaining empty, because not every situation uses any type encountered.
|
||||
* wouldn't it be desirable to have multiple distinct contexts, each with
|
||||
* its own set of Type-IDs and maybe also separate locking?
|
||||
* Is this issue worth the hassle? //////////////////////////////TICKET #169
|
||||
* AllocationCluster owns a heterogeneous collection of objects of various types.
|
||||
* Typically, allocation happens during a short time span when building a new segment,
|
||||
* and objects are used together until the segment is discarded. The primary leverage
|
||||
* is to bulk-allocate memory, and to avoid invoking destructors (and thus to access
|
||||
* a lot of _cache-cold memory pages_ on clean-up). A Stdlib compliant #Allocator
|
||||
* is provided for use with STL containers. The actual allocation uses heap memory
|
||||
* in _extents_ of hard-wired size, by the accompanying StorageManager.
|
||||
* @warning use #createDisposable whenever possible, but be sure to understand
|
||||
* the ramifications of _not invoking_ an object's destructor.
|
||||
*/
|
||||
class AllocationCluster
|
||||
: util::MoveOnly
|
||||
|
|
@ -121,17 +106,11 @@ namespace lib {
|
|||
};
|
||||
Storage storage_;
|
||||
|
||||
|
||||
public:
|
||||
AllocationCluster ();
|
||||
~AllocationCluster () noexcept;
|
||||
|
||||
|
||||
template<class TY, typename...ARGS>
|
||||
TY& create (ARGS&& ...);
|
||||
|
||||
template<class TY, typename...ARGS>
|
||||
TY& createDisposable (ARGS&& ...);
|
||||
|
||||
template<typename X>
|
||||
Allocator<X>
|
||||
getAllocator()
|
||||
|
|
@ -140,6 +119,13 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
template<class TY, typename...ARGS>
|
||||
TY& create (ARGS&& ...);
|
||||
|
||||
template<class TY, typename...ARGS>
|
||||
TY& createDisposable (ARGS&& ...);
|
||||
|
||||
|
||||
/* === diagnostics === */
|
||||
|
||||
size_t numExtents() const;
|
||||
|
|
@ -168,14 +154,32 @@ namespace lib {
|
|||
return static_cast<X*> (allotMemory (cnt * sizeof(X), alignof(X)));
|
||||
}
|
||||
|
||||
typedef void (*DtorInvoker) (void*);
|
||||
|
||||
class Destructor
|
||||
: util::NonCopyable
|
||||
{
|
||||
public:
|
||||
virtual ~Destructor(); ///< this is an interface
|
||||
Destructor* next{nullptr};// intrusive linked list...
|
||||
};
|
||||
|
||||
/** @internal storage frame with the actual payload object,
|
||||
* which can be attached to a list of destructors to invoke
|
||||
*/
|
||||
template<typename X>
|
||||
void* allotWithDeleter();
|
||||
struct AllocationWithDestructor
|
||||
: Destructor
|
||||
{
|
||||
X payload;
|
||||
|
||||
template<typename...ARGS>
|
||||
AllocationWithDestructor (ARGS&& ...args)
|
||||
: payload(std::forward<ARGS> (args)...)
|
||||
{ }
|
||||
};
|
||||
|
||||
void expandStorage (size_t);
|
||||
void registerDestructor (void*);
|
||||
void discardLastDestructor();
|
||||
void registerDestructor (Destructor&);
|
||||
bool _is_within_limits (size_t,size_t);
|
||||
|
||||
friend class test::AllocationCluster_test;
|
||||
|
|
@ -187,13 +191,22 @@ namespace lib {
|
|||
|
||||
//-----implementation-details------------------------
|
||||
|
||||
/**
|
||||
* Factory function: place a new instance into this AllocationCluster,
|
||||
* but *without invoking its destructor* on clean-up (for performance reasons).
|
||||
*/
|
||||
template<class TY, typename...ARGS>
|
||||
TY&
|
||||
AllocationCluster::createDisposable (ARGS&& ...args)
|
||||
{
|
||||
return * new(allot<TY>()) TY (std::forward<ARGS> (args)...);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory function: place a new instance into this AllocationCluster;
|
||||
* the object will be properly destroyed when the cluster goes out of scope.
|
||||
* @note whenever possible, the #createDisposable variant should be preferred
|
||||
*/
|
||||
template<class TY, typename...ARGS>
|
||||
TY&
|
||||
AllocationCluster::create (ARGS&& ...args)
|
||||
|
|
@ -201,59 +214,10 @@ namespace lib {
|
|||
if constexpr (std::is_trivial_v<TY>)
|
||||
return createDisposable<TY> (std::forward<ARGS> (args)...);
|
||||
|
||||
void* storage = allotWithDeleter<TY>();
|
||||
try {
|
||||
return * new(storage) TY (std::forward<ARGS> (args)...);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
discardLastDestructor();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish a storage arrangement with a callback to invoke the destructor.
|
||||
* @remark the purpose of AllocationCluster is to avoid deallocation of individual objects;
|
||||
* thus the position and type of allocated payload objects is discarded. However,
|
||||
* sometimes it is desirable to ensure invocation of object destructors; in this case,
|
||||
* a linked list of destructor callbacks is hooked up in the storage extent. These
|
||||
* callback records are always allocated directly before the actual payload object,
|
||||
* and use a special per-type trampoline function to invoke the destructor, passing
|
||||
* a properly adjusted self-pointer.
|
||||
*/
|
||||
template<typename X>
|
||||
void*
|
||||
AllocationCluster::allotWithDeleter()
|
||||
{
|
||||
/**
|
||||
* Memory layout frame to place a payload object
|
||||
* and store a destructor callback as intrusive linked list.
|
||||
* @note this object is never constructed, but it is used to
|
||||
* reinterpret the StorageManager::Destructor record,
|
||||
* causing invocation of the destructor of the payload object,
|
||||
* which is always placed immediately behind.
|
||||
*/
|
||||
struct TypedDtorInvoker
|
||||
{
|
||||
void* next;
|
||||
DtorInvoker dtor;
|
||||
X payload;
|
||||
|
||||
/** trampoline function: invoke the destructor of the payload type */
|
||||
static void
|
||||
invokePayloadDtor (void* self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
TypedDtorInvoker* instance = static_cast<TypedDtorInvoker*> (self);
|
||||
instance->payload.~X();
|
||||
}
|
||||
};
|
||||
|
||||
TypedDtorInvoker* allocation = allot<TypedDtorInvoker>();
|
||||
allocation->dtor = &TypedDtorInvoker::invokePayloadDtor;
|
||||
registerDestructor (allocation);
|
||||
return & allocation->payload;
|
||||
using Frame = AllocationWithDestructor<TY>;
|
||||
auto& frame = createDisposable<Frame> (std::forward<ARGS> (args)...);
|
||||
registerDestructor (frame);
|
||||
return frame.payload;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -323,20 +323,6 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
/** extract the top-most element, if any
|
||||
* @warning gives up ownership; if this list manages ownership,
|
||||
* then the caller is responsible for deallocating the removed entry
|
||||
* @return pointer to the removed element
|
||||
*/
|
||||
N*
|
||||
pop()
|
||||
{
|
||||
N* elm = head_;
|
||||
if (head_)
|
||||
head_ = head_->next;
|
||||
return elm;
|
||||
}
|
||||
|
||||
|
||||
/** prepend object of type TY, forwarding ctor args */
|
||||
template<class TY =N, typename...ARGS>
|
||||
|
|
|
|||
|
|
@ -290,14 +290,9 @@ namespace test {
|
|||
CHECK (i3 == 42);
|
||||
|
||||
// allocate a "disposable" object (dtor will not be called)
|
||||
SHOW_EXPR(clu.numBytes())
|
||||
SHOW_EXPR(posOffset())
|
||||
size_t pp = posOffset();
|
||||
auto& o1 = clu.createDisposable<Dummy<2>> (4);
|
||||
CHECK (o1.getID() == 4);
|
||||
SHOW_EXPR(clu.numBytes())
|
||||
SHOW_EXPR(posOffset())
|
||||
SHOW_EXPR(checksum)
|
||||
markSum = checksum;
|
||||
CHECK (checksum == 4+4);
|
||||
CHECK (alignof(Dummy<2>) == alignof(char));
|
||||
|
|
@ -309,11 +304,27 @@ SHOW_EXPR(checksum)
|
|||
auto& o2 = clu.create<Dummy<2>> (8);
|
||||
CHECK (o2.getID() == 8);
|
||||
CHECK (checksum == markSum + 8+8);
|
||||
SHOW_EXPR(clu.numBytes())
|
||||
CHECK (posOffset() - pp > sizeof(Dummy<2>) + 2*sizeof(void*));
|
||||
CHECK (slot(1) > 0);
|
||||
CHECK (size_t(&o2) - slot(1) == 2*sizeof(void*)); // Object resides in a Destructor frame,
|
||||
using Dtor = AllocationCluster::Destructor; // ... which has been hooked up into admin-slot-1 of the current extent
|
||||
auto dtor = (Dtor*)slot(1);
|
||||
CHECK (dtor->next == nullptr);
|
||||
|
||||
// any other object with non-trivial destructor....
|
||||
string rands = lib::test::randStr(9);
|
||||
pp = posOffset();
|
||||
string& s1 = clu.create<string> (rands);
|
||||
SHOW_EXPR(pp)
|
||||
SHOW_EXPR(posOffset())
|
||||
SHOW_EXPR(checksum)
|
||||
SHOW_EXPR(size_t(&s1))
|
||||
CHECK (posOffset() - pp >= sizeof(string) + 2*sizeof(void*));
|
||||
CHECK (size_t(&s1) - slot(1) == 2*sizeof(void*)); // again the Destructor frame is placed immediately before the object
|
||||
auto dtor2 = (Dtor*)slot(1); // and it has been prepended to the destructors-list in current extent
|
||||
SHOW_EXPR(size_t(dtor2->next))
|
||||
CHECK (dtor2->next == dtor); // with the destructor of o2 hooked up behind
|
||||
CHECK (dtor->next == nullptr);
|
||||
}
|
||||
SHOW_EXPR(checksum)
|
||||
CHECK (checksum == markSum);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81716,7 +81716,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#338800" CREATED="1715990297583" ID="ID_389684421" MODIFIED="1715990309548" TEXT="direkt per Standard-Allocator belegen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715990310261" ID="ID_1768477879" MODIFIED="1715990332985" TEXT="Idee: stattdessen virtuell eine Extent-Struktur mit Linked-Elements erzeugen">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#42646b" CREATED="1715990310261" ID="ID_1768477879" MODIFIED="1716657839389" TEXT="Idee: stattdessen virtuell eine Extent-Struktur mit Linked-Elements erzeugen">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1715991737062" ID="ID_690246579" MODIFIED="1715991797332" TEXT="Zweck: absolutes Minimum an Overhead">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -81754,8 +81754,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1716130707355" ID="ID_596338208" MODIFIED="1716130715686" TEXT="Korrektheit verifizieren...">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
<node COLOR="#338800" CREATED="1716130707355" ID="ID_596338208" MODIFIED="1716657825150" TEXT="Korrektheit verifizieren...">
|
||||
<arrowlink COLOR="#66a9c6" DESTINATION="ID_1042988047" ENDARROW="Default" ENDINCLINATION="634;-58;" ID="Arrow_ID_1847513597" STARTARROW="None" STARTINCLINATION="1082;0;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715820305436" ID="ID_1741026762" MODIFIED="1715820308396" TEXT="Clean-up">
|
||||
|
|
@ -81768,8 +81769,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<arrowlink COLOR="#faf8b2" DESTINATION="ID_1028046936" ENDARROW="Default" ENDINCLINATION="102;3;" ID="Arrow_ID_1495010693" STARTARROW="None" STARTINCLINATION="118;4;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1716130029614" ID="ID_229036433" MODIFIED="1716604728822" TEXT="automatischer Destruktor-Aufruf">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1716130029614" ID="ID_229036433" MODIFIED="1716657674986" TEXT="automatischer Destruktor-Aufruf">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1716130041704" ID="ID_1028046936" MODIFIED="1716130101251" TEXT="kann getriggert werden von StorageManager::Destructor">
|
||||
<linktarget COLOR="#faf8b2" DESTINATION="ID_1028046936" ENDARROW="Default" ENDINCLINATION="102;3;" ID="Arrow_ID_1495010693" SOURCE="ID_350853857" STARTARROW="None" STARTINCLINATION="118;4;"/>
|
||||
</node>
|
||||
|
|
@ -81821,17 +81822,28 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#338800" CREATED="1716604651319" ID="ID_398123666" MODIFIED="1716604673317" TEXT="muß sicherstellen, daß Destroctor-Record und Objekt beieinander liegen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1716606608657" ID="ID_1834443608" MODIFIED="1716606616344" TEXT="geht das nicht einfacher und sauberer?">
|
||||
<node COLOR="#435e98" CREATED="1716606608657" ID="ID_1834443608" MODIFIED="1716657600316" TEXT="geht das nicht einfacher und sauberer?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1716606623571" ID="ID_1928898649" MODIFIED="1716606636617" TEXT="im Grunde ist das hier ganz gewöhnlicher Polymorphismus"/>
|
||||
<node CREATED="1716606637660" ID="ID_1428982691" MODIFIED="1716606656903" TEXT="nur „zu fuß“ implementiert">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1716606637660" ID="ID_1428982691" MODIFIED="1716657605610" TEXT="nur „zu fuß“ implementiert">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716606714899" ID="ID_631957038" MODIFIED="1716606741395" TEXT="der Deleter-Invoker könnte durch eine VTable ersetzt werden">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1716606714899" ID="ID_631957038" MODIFIED="1716657619321" TEXT="der Deleter-Invoker könnte durch eine VTable ersetzt werden">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#31739f" CREATED="1716657620591" ID="ID_1357142766" MODIFIED="1716657653856" TEXT="puh.... viel einfacher">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" CREATED="1716657678423" ID="ID_567905569" LINK="https://en.cppreference.com/w/cpp/named_req/TrivialType" MODIFIED="1716657768484" TEXT="wird nicht verwendet bei »trivialen Typen«">
|
||||
<node CREATED="1716657717681" ID="ID_739380369" MODIFIED="1716657732347" TEXT="Skalare (numerics, pointer)"/>
|
||||
<node CREATED="1716657733587" ID="ID_1787247560" MODIFIED="1716657739437" TEXT="triviale Klassen">
|
||||
<node CREATED="1716657746230" ID="ID_1898446055" MODIFIED="1716657751752" TEXT="trivial kopierbar"/>
|
||||
<node CREATED="1716657752197" ID="ID_1032964700" MODIFIED="1716657755873" TEXT="trivial konstruierbar"/>
|
||||
</node>
|
||||
<node CREATED="1716657739926" ID="ID_717834034" MODIFIED="1716657744715" TEXT="Arrays derselben"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1716130724127" ID="ID_727448469" MODIFIED="1716133312180" TEXT="low-level-Test">
|
||||
|
|
@ -81839,14 +81851,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1716130730820" ID="ID_539013579" MODIFIED="1716130744964" TEXT="ich mache hier gefährliche Sachen">
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130764415" ID="ID_966285930" MODIFIED="1716130831111" TEXT="explizit zu verifizieren">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1716130764415" ID="ID_966285930" MODIFIED="1716657861262" TEXT="explizit zu verifizieren">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1716130773434" ID="ID_643589646" MODIFIED="1716130792420" TEXT="Destruktoren werden aufgerufen ⟹ Prüfsumme"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130797235" ID="ID_532362151" MODIFIED="1716130811753" TEXT="Pointer und Größe werden korrekt bewegt">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1716130773434" ID="ID_643589646" MODIFIED="1716657856744" TEXT="Destruktoren werden aufgerufen ⟹ Prüfsumme">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716130812393" ID="ID_136785264" MODIFIED="1716130824328" TEXT="Connectivity der virtuellen Management-Datenstruktur">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1716130797235" ID="ID_532362151" MODIFIED="1716657668978" TEXT="Pointer und Größe werden korrekt bewegt">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1716130812393" ID="ID_136785264" MODIFIED="1716657670466" TEXT="Connectivity der virtuellen Management-Datenstruktur">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1716130832134" ID="ID_1783945506" MODIFIED="1716133346231" TEXT="hierfür einen friend-Test schaffen">
|
||||
|
|
@ -81936,7 +81950,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1716552190584" ID="ID_1042988047" MODIFIED="1716593224739" TEXT="einen Überlauf provozieren">
|
||||
<node COLOR="#338800" CREATED="1716552190584" ID="ID_1042988047" MODIFIED="1716657825151" TEXT="einen Überlauf provozieren">
|
||||
<linktarget COLOR="#66a9c6" DESTINATION="ID_1042988047" ENDARROW="Default" ENDINCLINATION="634;-58;" ID="Arrow_ID_1847513597" SOURCE="ID_596338208" STARTARROW="None" STARTINCLINATION="1082;0;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1716605425287" ID="ID_1793345065" MODIFIED="1716605442774" TEXT="Objekt-Allokation mit registriertem Destruktor">
|
||||
|
|
@ -81945,8 +81960,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node BACKGROUND_COLOR="#c8c0b6" CREATED="1716605469169" ID="ID_680488739" MODIFIED="1716605487862" TEXT="zusätzliche Storage belegt"/>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" CREATED="1716605475561" ID="ID_43688892" MODIFIED="1716605487863" TEXT="Destruktor wird aufgerufen"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716605489686" ID="ID_838033504" MODIFIED="1716605500558" TEXT="Verzeigerung explizit verifizieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1716605489686" ID="ID_838033504" MODIFIED="1716657867989" TEXT="Verzeigerung explizit verifizieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716552266490" ID="ID_34007851" MODIFIED="1716552275535" TEXT="weiteren Überlauf mit Alignment">
|
||||
|
|
|
|||
Loading…
Reference in a new issue