Library: reassess logic to reject some types for existing container

`lib::Several` is designed to be highly adaptable, allowing for
several quite distinct usage styles. On the downside, this requires
to perform some checks at runtime only, since the ability to handle
some element depends on specific circumstances.

This is a notable difference to `std::vector`, which is simply not capable
of handling ''non-copyable'' types, even if given an up-front memory reservation.

The last test case provided with the previous changeset did not trigger
an exception, but closer investigation revealed that this is correct,
since in this specific situation the container can accept this object type,
thereby just loosing the ability to move-relocate further objects.

A slightly re-arranged test scenario can be used to demonstrate this fine point.
This commit is contained in:
Fischlurch 2024-06-12 17:07:55 +02:00
parent d9f86ad891
commit 85e3780a34
3 changed files with 184 additions and 21 deletions

View file

@ -89,10 +89,12 @@ namespace lib {
using util::max;
using util::min;
using util::_Fmt;
using std::is_nothrow_move_constructible_v;
using std::is_trivially_move_constructible_v;
using std::is_trivially_destructible_v;
using std::has_virtual_destructor_v;
using std::is_trivially_copyable_v;
using std::is_copy_constructible_v;
using std::is_object_v;
using std::is_volatile_v;
using std::is_const_v;
@ -241,11 +243,21 @@ namespace lib {
std::memmove (newPos, oldPos, amount);
}
else
if constexpr (is_nothrow_move_constructible_v<E>
or is_copy_constructible_v<E>)
{
E& oldElm = reinterpret_cast<E&> (src->subscript (idx));
Fac::template createAt<E> (tar, idx
,std::move_if_noexcept (oldElm));
}
else
{
NOTREACHED("realloc immovable type (neither trivially nor typed movable)");
// this alternative code section is very important, because it allows
// to instantiate this code even for »noncopyable« types, assuming that
// sufficient storage is reserved beforehand, and thus copying is irrelevant.
// For context: the std::vector impl. from libStdC++ is lacking this option.
}
tar->cnt = idx+1; // mark fill continuously for proper clean-up after exception
}
};
@ -516,7 +528,7 @@ namespace lib {
*/
template<typename TY>
Deleter
selectDestructor ()
selectDestructor()
{
typename POL::Fac& factory(*this);

View file

@ -288,6 +288,12 @@ SHOW_EXPR(ne5.getVal())
builder.fillElm(5);
CHECK (5 == builder.size());
// trigger re-alloc by moving into larger memory block
builder.fillElm(14);
CHECK (19 == builder.size());
builder.emplace<short>();
builder.emplace<Num<1>>(); ///////////////////////////////////OOO this should trigger an exception -> need to code an explicit check right at the start of emplaceNewElm()
}
}

View file

@ -82741,24 +82741,81 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1717980838451" ID="ID_123345043" MODIFIED="1717980849735" TEXT="hab es jetzt vorerst doch wieder dorthin geschoben"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717980850354" ID="ID_1951694568" MODIFIED="1718158733534" TEXT="TODO: bessere L&#xf6;sung finden">
<linktarget COLOR="#ea004d" DESTINATION="ID_1951694568" ENDARROW="Default" ENDINCLINATION="456;43;" ID="Arrow_ID_13456577" SOURCE="ID_1048202028" STARTARROW="None" STARTINCLINATION="325;-27;"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717980850354" ID="ID_1951694568" MODIFIED="1718200585346" TEXT="diese L&#xf6;sung nochmal &#xfc;berpr&#xfc;fen">
<linktarget COLOR="#77334a" DESTINATION="ID_1951694568" ENDARROW="Default" ENDINCLINATION="466;38;" ID="Arrow_ID_13456577" SOURCE="ID_1048202028" STARTARROW="None" STARTINCLINATION="325;-27;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1718200372590" HGAP="61" ID="ID_523646974" MODIFIED="1718200393353" TEXT="m&#xf6;glicherweise wird die L&#xf6;sung sehr Kontext-abh&#xe4;ngig" VSHIFT="11">
<icon BUILTIN="idea"/>
<node CREATED="1718200410241" HGAP="22" ID="ID_341859477" MODIFIED="1718200510931" TEXT="unter Umst&#xe4;nden mu&#xdf; man gar nicht unterbinden, was kein Problem darstellt" VSHIFT="9"/>
<node CREATED="1718200437669" ID="ID_332242965" MODIFIED="1718200499116" TEXT="solange Objekte nicht verschoben werden m&#xfc;ssen, ist der konkrete Typ irrelevant">
<linktarget COLOR="#fdfac6" DESTINATION="ID_332242965" ENDARROW="Default" ENDINCLINATION="-228;8;" ID="Arrow_ID_950941369" SOURCE="ID_534883946" STARTARROW="None" STARTINCLINATION="266;9;"/>
</node>
<node CREATED="1718200462555" ID="ID_1692266338" MODIFIED="1718200470609" TEXT="nur den Destruktor mu&#xdf; man aufrufen k&#xf6;nnen"/>
<node CREATED="1718201691476" HGAP="3" ID="ID_357179310" MODIFIED="1718201781484" TEXT="&#xfc;berpr&#xfc;ft und getestet: ist korrekt" VSHIFT="13">
<arrowlink COLOR="#51b6cc" DESTINATION="ID_1592892204" ENDARROW="Default" ENDINCLINATION="281;-14;" ID="Arrow_ID_517622740" STARTARROW="None" STARTINCLINATION="313;27;"/>
</node>
</node>
</node>
</node>
<node CREATED="1717894410331" ID="ID_732905043" MODIFIED="1717894437670" TEXT="es gen&#xfc;gt, die move_lock-Flag zu pr&#xfc;fen">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1717894472499" ID="ID_534883946" MODIFIED="1717894525092" TEXT="Aber: wird erst relevant wenn tats&#xe4;chlich Objekte verschoben werden m&#xfc;ssen">
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1717894472499" ID="ID_534883946" MODIFIED="1718200561076" TEXT="Aber: wird erst relevant wenn tats&#xe4;chlich Objekte verschoben werden m&#xfc;ssen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...und das kann vom Allokator abh&#228;ngen
...und das kann vom Allokator abh&#228;ngen &#8212; sollte also in den meisten f&#252;r Lumiera wirklich relevanten F&#228;llen gar nicht vorkommen
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#fdfac6" DESTINATION="ID_332242965" ENDARROW="Default" ENDINCLINATION="-228;8;" ID="Arrow_ID_950941369" STARTARROW="None" STARTINCLINATION="266;9;"/>
<icon BUILTIN="flag-pink"/>
<node CREATED="1718202386482" HGAP="264" ID="ID_875355344" MODIFIED="1718202419463" TEXT="au&#xdf;erdem: sicherstellen da&#xdf; nur valider Copy/Move-Code generiert wird" VSHIFT="38">
<icon BUILTIN="yes"/>
<node CREATED="1718202425005" ID="ID_787831291" MODIFIED="1718202718252" TEXT="extrem wichtig &#x2014; das ist eine Schw&#xe4;che von std::vector">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...nicht nur eine Schw&#228;che, sondern ein ausgewachsenes &#196;rgerniss. Allerdings betrifft das strenggenommen nur die libStc++
</p>
<p>
Und zwar ist es so: man k&#246;nnte einen Vector per resize() vordimensionieren, so da&#223; die Storage nicht per alloc-and-copy wachsen mu&#223;; danach k&#246;nnte man eigentlich ohne Weiteres auch non-copyable-Objekte im Vector haben &#8212; solange man den Vector selber ebenfalls nicht kopiert (Verschieben w&#228;re m&#246;glich).
</p>
<p>
</p>
<p>
Soweit <i>die Theorie...</i>&#160;in der Praxis aber <b>scheitert das</b>, weil der Compiler versucht, den realloc-Code zu instantiieren und daf&#252;r keinen Copy/Move-Konstruktor findet
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1718202443155" ID="ID_1046115206" MODIFIED="1718202851765" TEXT="wir wollen definitiv auch non-copyable-Objekte handhaben k&#xf6;nnen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Und dazu sind wir im Stande...
</p>
<ul>
<li>
wir haben entsprechende Pr&#252;f-Logik, die zur Laufzeit eine Exception wirft, wenn die Kapazit&#228;t nicht reicht. Da Objekte nur im Builder hinzugef&#252;gt werden, ist das hier viel akzeptabler als f&#252;r std::vector, der durch ein solches Verhalten ja doch massiv unzuverl&#228;ssig w&#252;rde.
</li>
<li>
wir m&#252;ssen dann nur sicherstellen, da&#223; der typisierte copy-Code in unserer realloc()-Funktion ebenfalls einen statischen Guard hat, und damit auch &#252;berhaupt nicht emittiert wird, wenn wir ihn ohnehin nicht nutzen k&#246;nnen
</li>
</ul>
</body>
</html>
</richcontent>
</node>
<node CREATED="1718202456849" ID="ID_1146034926" MODIFIED="1718202534877" TEXT="das auch testen!">
<arrowlink COLOR="#638ad5" DESTINATION="ID_247674037" ENDARROW="Default" ENDINCLINATION="-635;-37;" ID="Arrow_ID_10606647" STARTARROW="None" STARTINCLINATION="-429;58;"/>
</node>
</node>
</node>
</node>
</node>
@ -82894,6 +82951,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</p>
</body>
</html></richcontent>
<node CREATED="1718202490965" ID="ID_247674037" MODIFIED="1718202528909" TEXT="Handhabung von non-copyable-Objekten">
<linktarget COLOR="#638ad5" DESTINATION="ID_247674037" ENDARROW="Default" ENDINCLINATION="-635;-37;" ID="Arrow_ID_10606647" SOURCE="ID_1146034926" STARTARROW="None" STARTINCLINATION="-429;58;"/>
</node>
</node>
<node CREATED="1717771640460" ID="ID_1646507168" MODIFIED="1717771661118" TEXT="weil die Datenstruktur doch so sch&#xf6;n elegant sein sollte....">
<icon BUILTIN="smiley-oh"/>
@ -83110,9 +83170,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1718151025411" ID="ID_1523821713" MODIFIED="1718151039915" TEXT="die w&#xe4;re nur erlaubt bei (bisher) leerem Builder"/>
<node COLOR="#5b280f" CREATED="1718151047944" ID="ID_1701216144" MODIFIED="1718151087039" TEXT="(theoretisch k&#xf6;nnte man auch umkopieren, allerdings nur manchmal)">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...also ist das keine gute Idee, da verwirrend
@ -83349,9 +83407,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1718146553609" ID="ID_543025538" MODIFIED="1718146642666" TEXT="kann kein char[] direkt erstellen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...und zwar, weil man ein (language)-Array mit operator new[] allozieren mu&#223;
@ -83384,9 +83440,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#761b6d" CREATED="1718158901756" ID="ID_1578123647" MODIFIED="1718158939699">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
und der von Dummy mu&#223; <b>noexcept</b>&#160;sein
@ -83397,22 +83451,113 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="broken-line"/>
</node>
</node>
<node CREATED="1718122077386" ID="ID_959961694" MODIFIED="1718122087388" TEXT="kann keinen anderen Typ platzieren (selbst wenn kleiner)">
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1718157829884" ID="ID_1228814618" MODIFIED="1718157836660" TEXT="spricht nicht an">
<node COLOR="#865c48" CREATED="1718122077386" ID="ID_959961694" MODIFIED="1718201948324" TEXT="kann keinen anderen Typ platzieren (selbst wenn kleiner)">
<icon BUILTIN="closed"/>
<node COLOR="#5b280f" CREATED="1718157829884" ID="ID_1228814618" MODIFIED="1718201060734" TEXT="spricht nicht an">
<icon BUILTIN="broken-line"/>
<icon BUILTIN="button_cancel"/>
<node CREATED="1718157847914" ID="ID_1926254706" MODIFIED="1718157851469" TEXT="Beobachtungen">
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1718157852441" ID="ID_1384707564" MODIFIED="1718157871000" TEXT="probeMoveCapability&lt;TY&gt;() setzt gleich zu Beginn die move-Sperre">
<node COLOR="#435e98" CREATED="1718157852441" ID="ID_1384707564" MODIFIED="1718201634118" TEXT="probeMoveCapability&lt;TY&gt;() setzt gleich zu Beginn die move-Sperre">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1718158012556" ID="ID_240735780" MODIFIED="1718158019734" TEXT="das ist logisch falsch...."/>
<node CREATED="1718158020275" ID="ID_1916533180" MODIFIED="1718158029781" TEXT="wir d&#xfc;rften diesen Punkt gar nicht erreichen"/>
<node COLOR="#5b280f" CREATED="1718158012556" ID="ID_240735780" MODIFIED="1718200763841" TEXT="das ist logisch falsch....">
<icon BUILTIN="button_cancel"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1718200610682" ID="ID_425914071" MODIFIED="1718200632697" TEXT="wirklich?">
<icon BUILTIN="help"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1718158031369" ID="ID_1048202028" MODIFIED="1718158733534" TEXT="Ja... hier fehlt ein expliziter Check">
<arrowlink COLOR="#ea004d" DESTINATION="ID_1951694568" ENDARROW="Default" ENDINCLINATION="456;43;" ID="Arrow_ID_13456577" STARTARROW="None" STARTINCLINATION="325;-27;"/>
<node CREATED="1718200615784" ID="ID_1636929590" MODIFIED="1718200869840" TEXT="genau genommen ist es korrekt">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Es ist n&#228;mlich so: wenn wir gleich die Move-Sperre setzen, k&#246;nnen wir ansonsten das Objekt durchaus reinlassen &#8212; vorausgesetzt das mit dem Destruktor bleibt OK &#8212; und letzteres pr&#252;fen wir ja auch, nur eben sp&#228;ter (aus Gr&#252;nden der einfachen Formulierung im Code, weil wir den R&#252;ckgabewert von dieser Pr&#252;fung erst sp&#228;ter brauchen)
</p>
</body>
</html></richcontent>
</node>
</node>
<node COLOR="#5b280f" CREATED="1718158020275" ID="ID_1916533180" MODIFIED="1718201643476" TEXT="wir d&#xfc;rften diesen Punkt gar nicht erreichen">
<icon BUILTIN="button_cancel"/>
<node CREATED="1718201646955" HGAP="31" ID="ID_100839325" MODIFIED="1718201656323" TEXT="doch: man kann es so machen" VSHIFT="14"/>
</node>
</node>
<node COLOR="#5b280f" CREATED="1718158031369" ID="ID_1048202028" MODIFIED="1718201789622" TEXT="Ja... hier fehlt ein expliziter Check">
<arrowlink COLOR="#77334a" DESTINATION="ID_1951694568" ENDARROW="Default" ENDINCLINATION="466;38;" ID="Arrow_ID_13456577" STARTARROW="None" STARTINCLINATION="325;-27;"/>
<icon BUILTIN="broken-line"/>
<icon BUILTIN="button_cancel"/>
<node COLOR="#5b280f" CREATED="1718200660533" HGAP="30" ID="ID_1440476684" MODIFIED="1718200699309" TEXT="nicht klar ob der tats&#xe4;chlich notwendig ist..." VSHIFT="18">
<icon BUILTIN="stop-sign"/>
</node>
<node CREATED="1718200685242" HGAP="32" ID="ID_722777194" MODIFIED="1718200696765" TEXT="es sind zwei getrennte Belange" VSHIFT="-1">
<icon BUILTIN="info"/>
<node CREATED="1718200700899" ID="ID_203165643" MODIFIED="1718200720954" TEXT="ein Objekt destruieren k&#xf6;nnen &#x27f5; stets verbindilch"/>
<node CREATED="1718200722421" ID="ID_1426680364" MODIFIED="1718200751665" TEXT="ein Objekt per copy/move-ctor verschieben &#x27f5; optional"/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1718201054552" ID="ID_1583618556" MODIFIED="1718201621216" TEXT="Analyse-Fazit">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node CREATED="1718201064639" ID="ID_536767559" MODIFIED="1718201202494">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
das im Test beobachtete Verhalten <b>ist korrekt</b>
</p>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...es spricht tats&#228;chlich nichts dagegen, diesen Fall auch nachtr&#228;glich noch zuzulassen &#8212; man gibt dann eben die M&#246;glichkeit f&#252;r re-Allocations auf (und wenn <i>das</i>&#160;ein Problem darstellt, macht sich das zu gegebener Zeit <i>eindeutig bemerkbar</i>)
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1718201084309" ID="ID_1592892204" MODIFIED="1718201766838" TEXT="die Pr&#xfc;f-Logik im Code ist bereits vollst&#xe4;ndig und gut angeordnet">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<ul>
<li>
gleich zu Beginn &#8212; noch vor allen Storage-Pr&#252;fungen &#8212; stellen wir fest, ob wir (noch) Ojbekte verschieben k&#246;nnen. Wenn das f&#252;r <i>ein einziges Objekt </i>nicht mehr gilt, dann gilt es eben f&#252;r den gesamten Container nicht mehr. Es ist zu dem Zeitpunkt noch nicht klar, ob das &#252;berhaupt ein Problem darstellt.
</li>
<li>
als N&#228;chstes pr&#252;fen wir die Speicheranforderungen; wenn der Speicher <i>nicht reicht</i>&#160;und wir zudem <i>nicht verschieben k&#246;nnen, </i>dann staubt's
</li>
<li>
nur wenn n&#246;tig <b>und m&#246;glich</b>&#160;wird die Allokation vergr&#246;&#223;ert. An dem Punkt ist alles wieder sauber <i>f&#252;r die bestehenden Elemente</i>
</li>
<li>
erst danach m&#252;ssen wir die Destruktor-M&#246;glichkeit <b>f&#252;r das neue Element</b>&#160;pr&#252;fen. Wenn hier ein Fehler auftritt, wurde zwar ggfs der Puffer (unn&#246;tigerweise) vergr&#246;&#223;ert, aber es hat noch keine Objekt-Konstruktion stattgefunden, und wir die Gesamtsituation ist weiterhin konsistent
</li>
</ul>
</body>
</html></richcontent>
<linktarget COLOR="#51b6cc" DESTINATION="ID_1592892204" ENDARROW="Default" ENDINCLINATION="281;-14;" ID="Arrow_ID_517622740" SOURCE="ID_357179310" STARTARROW="None" STARTINCLINATION="313;27;"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718201601397" ID="ID_782023787" MODIFIED="1718201981335" TEXT="entsprechend den Test umformulieren">
<arrowlink COLOR="#6079c7" DESTINATION="ID_357857724" ENDARROW="Default" ENDINCLINATION="192;-8;" ID="Arrow_ID_654254378" STARTARROW="None" STARTINCLINATION="-163;11;"/>
<icon BUILTIN="yes"/>
</node>
</node>
</node>
</node>
<node CREATED="1718201827718" ID="ID_357857724" MODIFIED="1718201975615">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
kann keinen <i>ganz anderen </i>Typ platzieren (der nicht Subklasse ist)
</p>
</body>
</html></richcontent>
<linktarget COLOR="#6079c7" DESTINATION="ID_357857724" ENDARROW="Default" ENDINCLINATION="192;-8;" ID="Arrow_ID_654254378" SOURCE="ID_782023787" STARTARROW="None" STARTINCLINATION="-163;11;"/>
<font NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1718201899221" ID="ID_1719848161" MODIFIED="1718201919629" TEXT="wenn man eine Subklasse platziert, wird die M&#xf6;glichkeit f&#xfc;r Wachstum beschnitten"/>
</node>
<node CREATED="1718122252659" ID="ID_616405505" MODIFIED="1718122291873" TEXT="Triviale Typen">
<node CREATED="1718122293022" ID="ID_697520417" MODIFIED="1718122302248" TEXT="kann wachsen"/>