C++20 Tutorial/Howto: Concepts
-
@hustbaer sagte in C++20 Tutorial/Howto: Concepts:
Ich kann die fatalistische Einstellung gegenüber
bad_alloc
die viele Entwickler haben (darunter leider auch viele Library-Entwickler) auf jeden Fall nicht ganz verstehen.Ja, die "großen" Anforderungen bei bestimmten extern ausgelösten Aktionen sind ein gutes Argument. Ich werd das nochmal überdenken. Ich hatte hauptsächlich den Fitzelkram im Sinn, den jedes Programm permanent macht, 100 Byte für nen
std::string
hier, 4k für nen keinenstd::vector
-Buffer da. Ich denke die meisten Funktionen in beliebigem Code, diebad_alloc
werfen, werden eher in diesem Kontext verwendet. Wenn da nenbad_alloc
kommt, geht meist eh nicht viel mehr, als würdevoll mit ner Fehlermeldung auszusteigen - und das könnte auch Code im Umkreis vonterminate
erledigen.Vielleicht sind ja
noexcept
-Allokationen per Default eine Idee und die Exception-Varianten fordert man explizit an, z.B. wenn man eine Datei komplett in den Speicher laden oder anderes Sperrgut verarbeiten will. Derzeit ist es ja umgekehrt... das ist aber außerhalb eigener Bibliotheken eh ein Ding für die weitere Evolution der Standardbibliothek.
-
@Finnegan sagte in C++20 Tutorial/Howto: Concepts:
Oder kann man ausser in sehr speziellen Ausnahmefällen ein
bad_alloc
irgendwie sinnvoller behandeln, als es einterminate
ohnehin schon tut? Vor allem wenn man wahrscheinlich eh gar keinen Speicher mehr reservieren kann. Damit könnten wahrscheinlich jede Menge Funktionen (vor allem viele Konstruktoren)noexcept
werden. Auch wurde ich abseits von Bugs noch nie wirklich mitbad_alloc
s beworfen, und Bugs sind ja eher ein Fall fürassert
s (mag auf magereren Systemen anders aussehen).Programme, die Nutzereingaben bearbeiten, können sehr schnell bad_allocs bekommen, weil einfach die Nutzereingaben nicht passen. Allerdings ist in Zeiten von memory overcommitment das ganze Procedere ohnehin sehr zweifelhaft, da man kein bad_alloc bekommt sondern im Regelfall ein seg_fault beim Zugriff auf die Speicherseite, die nicht angelegt werden kann.
-
@VLSI_Akiko sagte in C++20 Tutorial/Howto: Concepts:
24 chars? -> aka small string optimization
Unterschiedlich je nach compiler.
-
@Finnegan sagte in C++20 Tutorial/Howto: Concepts:
Vielleicht sind ja
noexcept
-Allokationen per Default eine Idee und die Exception-Varianten fordert man explizit an, z.B. wenn man eine Datei komplett in den Speicher laden oder anderes Sperrgut verarbeiten will.Ohne zusätzliche Sprachfeatures wird das denke ich nix. Ich meine, so Sachen wir Strings-Konkatenieren oder mal schnell ein
push_back
auf nenvector
machen ist schon sehr praktisch. Oder Memory-Streams. Oder ca. 1'000'000 andere Dinge die dynamisch Speicher anfordern. Wenn man da überall manuell prüfen muss ob es geklappt hat... pfuh. Mühsam.
-
@hustbaer sagte in C++20 Tutorial/Howto: Concepts:
@Finnegan sagte in C++20 Tutorial/Howto: Concepts:
Vielleicht sind ja
noexcept
-Allokationen per Default eine Idee und die Exception-Varianten fordert man explizit an, z.B. wenn man eine Datei komplett in den Speicher laden oder anderes Sperrgut verarbeiten will.Ohne zusätzliche Sprachfeatures wird das denke ich nix. Ich meine, so Sachen wir Strings-Konkatenieren oder mal schnell ein
push_back
auf nenvector
machen ist schon sehr praktisch. Oder Memory-Streams. Oder ca. 1'000'000 andere Dinge die dynamisch Speicher anfordern. Wenn man da überall manuell prüfen muss ob es geklappt hat... pfuh. Mühsam.Die Idee ist ja gar nicht zu prüfen - exceptions sind schon klasse, das soll jetzt kein zurück-zu-errorcodes-Vorschlag sein. Der Allocator ruft dann im Fehlerfall einfach
terminate
auf, wenn er fürnoexcept
konfiguriert wurde. Und wenn nicht, dann bleibt alles beim alten.if constexpr (if_allocator_is_configured_for_noexcept<Alloc>) terminate(); else throw ...
oder noch banaler: die Funktion bekommt ein
noexcept
und wirft trotzdem.Lediglich das
vector::push_back
und andere müssten zusätzlich einen Specifier á lanoexcept(allocator_is_configured_for_noexcept<Alloc>)
bekommen. Sollte eigentlich ohne neue Sprachfeatures gehen. So zumindest meine naiv-spontane Vorstellung ... übersehe ich was (abgesehen von all dem Legacy-Code der meist nicht gut auf Änderung von Defaults reagiert) ?
-
@Jockelx sagte in C++20 Tutorial/Howto: Concepts:
Unterschiedlich je nach compiler.
Nope, das ist ein Implementierungsdetail der C++ Lib und ist nicht wirklich Bestandteil des Compilers. Genau genommen ist es ein Detail der STL seit C++98.
-
@VLSI_Akiko Von mir aus nenn es Implemtierung der Stl - es war klar (sollte klar gewesen sein), was gemeint ist.
-
@Finnegan Ach so meinst du das. @VLSI_Akiko hatte vorhin
new (std::nothrow)
erwähnt, daher hatte ich das im Kopf und dachte du beziehst dich darauf.Ja, es gibt auch einige Projekte die
operator new
überschreiben und darinterminate
aufrufen statt zu werfen. Oder C Projekte die bewusst auf Fehlerchecks beimalloc
verzeichten "weil's eh crasht" wenn man den Zeiger dann dereferenziert.operator new
überschreiben ist etwas, was ich auch noch irgendwo OK finde. Also wenn die Anwendung das macht, nicht wenn es irgendein bekifftes Framework macht das sich für etwas zu wichtig hält. Für manche Anwendungen ist das vermutlich völlig OK. Wenn man dann davon profitieren möchte, müsste man natürlich Änderungen an der Standard Library machen.noexcept(allocator_is_configured_for_noexcept<Alloc>)
Etwas ala
noexcept(noexcept(_MyAlloc.allocate(1)) && other_conditions)
sollte ausreichend sein.
-
@hustbaer sagte in C++20 Tutorial/Howto: Concepts:
@Finnegan Ach so meinst du das.
Ja, mir gehts vornehmlich darum, dass man damit wahrscheinlich eine reiche
noexcept
-Ernte einfahren könnte. Ich hab jetzt keine belastbaren Zahlen, aber mein Bauchgefühl sagt mir, dass gerade beibad_alloc
besonders viele Funktionennoexcept
werden könnten, die auch noch in besonderem Maße davon profitieren würden - ich behaupte mal, dass Allokationen gerade in Konstruktioren besonders häufig sind.noexcept(allocator_is_configured_for_noexcept<Alloc>)`
Etwas ala
noexcept(noexcept(_MyAlloc.allocate(1)) && other_conditions)
sollte ausreichend sein.Nun, ich habe
allocator_is_configured_for_noexcept<Alloc>
ja nicht definiert. Das kann ja durchaustemplate <typename Alloc> concept allocator_is_configured_for_noexcept = noexcept(_MyAlloc.allocate(1)) && other_conditions;
oer sowas sein ... ich glaube nicht, dass man das für jede Funktion alles hinschreiben wollte
-
Der
&& other_conditions
Teil wird ja nicht bei jeder Funktion gleich seinIch wollte damit nur darauf hinweisen dass man die Allokatoren nicht extra irgendwie "taggen" muss dass sie
noexcept
sind. Es würde einfach reichen sienoexcept
zu machen.Ich hab jetzt keine belastbaren Zahlen, aber mein Bauchgefühl sagt mir, dass gerade bei bad_alloc besonders viele Funktionen noexcept werden könnten, die auch noch in besonderem Maße davon profitieren würden - ich behaupte mal, dass Allokationen gerade in Konstruktioren besonders häufig sind.
Ja, klar. Die C++ Standard Library macht ja ausser Speicheranforderungen kaum Dinge die schief gehen können. Die grossen Gruppen sind:
bad_alloc
- Falsche Argumente (
vector::at
& Co) - IO Fehler (
std::filesystem
& Co)
Bis auf IO Fehler könnte man alles in vielen Programmen
noexcept
erklären und das Programm im Fall des Falles einfach abbrechen lassen.
-
Ich habe mal noch ein Beispiel für Concepts + variadic Templates ergänzt. Hierfür findet man erstaunlich wenige Information wie man das korrekt als Constraints verwendet.