ÜBerladung des operator new in c++11 und c++03
-
Ich habe vor kurzem mit GCC 4.7.2 (MinGW) gearbeitet, wobei ich für debuggingzwecke die operator new und operator delete überladen musste:
void* operator new(std::size_t n);
Mit Kommandozeilenargument -std=c++11 lief dies auch ganz gut, bis ich zwecks Test auf Rückwertskompatiblität auf -std=c++98 umgeschaltet habe, worauf mich eine Fehlermeldung auf das Fehlen der Exception-Spezifikation "throw(std::bad_alloc)" hinter operator new hingewiesen hat. Ich habe diese natürlich eingefügt und getestet, zwar hat der Compiler nun meine Arbeit klaglos angenommen, dafür funktionierte es aber auf c++11 nicht mehr, hier mit der Fehlermeldung, der Prototyp von operator new aus meinem Beispiel habe keine solche Spezifikation. So oder so hat der operator nur mit einem der beiden Standards funktioniert. Nach einem Blick in die Header-Übersicht von n3337 und in eine älteren Dokumentation bin ich überzeugt, dass diese Fehlermeldungen korrekt sind, so habe ich momentan einfach eine brute-force lösung gewählt, die zwar das Problem beseitigt, aber nicht besonders hübsch ist:
void* operator new(std::size_t n) #if __cplusplus < 201103L throw(std::bad_alloc) #endif ;
Und nun würde mich interessieren, ob es nicht eine elegantere Lösung gibt, die keine Nutzung des Präprozessors involviert, oder ich einen Fehler gemacht habe. Habe ich irgendetwas übersehen? Liegt es daran, dass der GCC c++11 nur experimentell unterstützt? Eine Suche im Internet und im Forum hat mir nichts nützliches gebracht.
(Ich muss zugeben, dass es eine Ewigkeit her ist, seit ich die operatoren new und delete das letzte Mal überladen habe.)
-
vorneweg, ich bin was die standards angeht absolut nicht wirklich involviert, aber von mir eine zwischenfrage
die exception spezifikationen sind doch nicht bindend für den compiler, oder?
es ist doch irgendwie so, dass der man trotz exception spezifikation andere exceptions werfen kann. und das führt schliesslich zu UB oder total schrägen dingen.wenn das also so ist
1.- wieso gibt es die spezifikationen denn überhaupt? (in java sind sie ja zwingend und da ist das ganz schön)
2.- wieso nutzen standard bibliotheken das dann?wenn dem nicht so ist, dann hab ich nix gesagt
-
Skym0sh0 schrieb:
die exception spezifikationen sind doch nicht bindend für den compiler, oder?
es ist doch irgendwie so, dass der man trotz exception spezifikation andere exceptions werfen kann. und das führt schliesslich zu UB oder total schrägen dingen.Nein, das führt zu std::terminate.
In C++11 sollen Exception Sezifikationen nicht mehr verwendet werden, deswegen der Unterschied bei new.
-
aber wieso sollen sie nicht verwendet werden?
es ist doch eigentlich nicht negativ, wenn folgendes irgendwo steht?!
void foo(int *, float, CFoo const&) throw(std::WaldUndWieseException);
weil dadurch sieht man ja recht schnell ob und was die funktion werfen könnte (natürlich neben namen, parameter, parameter typ, rückgabewert und so weiter)
also in java ist es ja pflicht (ausser bei unchecked exceptions)
-
-fno-enforce-eh-specs
Ist dein Freund.
Exception Spzifikationen sind böse. Am besten man deaktiviert sie.@Skym0sh0:
http://magazin.c-plusplus.net/artikel/Modernes Exception-Handling Teil 1 - Die Grundlagen :In C++ sind alle Exception-Spezifikationen optional und da der Check, welche Exception geworfen wird und welche geworfen werden dürfen, erst zur Laufzeit stattfindet, ist er ziemlich unnütz. Wenn eine unerlaubte Exception geworfen wird, wird die Funktion std::unexpected() aufgerufen, welche im Normalfall eine Exception vom Typ std::bad_exception wirft. Da aber, wie gesagt, diese Tests alle zur Laufzeit stattfinden, macht es keinen Sinn, in C++ Exception-Spezifikationen zu verwenden. Es kann vor allem auch gefährlich werden, da eben keine statischen Tests stattfinden, dass falsche Exception-Spezifikationen Fehler einführen. Und Fehler, die erst zur Laufzeit gefunden werden, sind die schwersten zu finden. Einige Compiler, wie zum Beispiel der Microsoft C++-Compiler, ignorieren Exception-Spezifikationen gleich vollständig.
-
Mir geht es hierbei zum großteil darum, ob der operator new tatsächlich eine nicht rückwärtskompatible Komponente darstellt, vor allem da der gesammte Rest von c++11 darauf ausgelegt ist, wie zum Beispiel die neuen allocator Anforderungen und selbst die tatsache, dass throw() und noexcept im Hinblick auf alte, vom Standard abgeleiteten Exceptions kompatibel sind.
-
Cachus schrieb:
Mir geht es hierbei zum großteil darum, ob der operator new tatsächlich eine nicht rückwärtskompatible Komponente darstellt, vor allem da der gesammte Rest von c++11 darauf ausgelegt ist, wie zum Beispiel die neuen allocator Anforderungen und selbst die tatsache, dass throw() und noexcept im Hinblick auf alte, vom Standard abgeleiteten Exceptions kompatibel sind.
Der gcc hat sehr blöde Exception-Spezifikationen. Deaktivier sie einfach.
Die meisten anderen Compiler haben hier weniger Probleme, da sie früher schon erkannt haben dass Exception-Spezifikationen dumm sind.
-
Das scheint mir arg Compilerabhängig. Gibt es keinen anderen Weg, fühle ich mich schon eher damit bedient, dass die Präprozessorversion dem Standard entspricht und ich mich von sonstigen Exception-Spezifikationen fernhalte. Schließlich war dies das erste Mal überhaupt, dass ich mit etwas anderem als throw() zu tun hatte.
-
Exception-Sepcs sind in C++ nicht Teil der Signatur, und mir wäre auch nicht bekannt dass irgendwas im Standard steht vonwegen dass der gloable operator new() eine zu haben hat wenn man ihn
überschreibtselbst definiert.Und... bekommst du von GCC mit -std=c++98 und ohne Exception-Spec wirklich einen Fehler oder bloss eine Warning?
-
hustbaer schrieb:
Exception-Sepcs sind in C++ nicht Teil der Signatur, und mir wäre auch nicht bekannt dass irgendwas im Standard steht vonwegen dass der gloable operator new() eine zu haben hat wenn man ihn
überschreibtselbst definiert.Sofern eine Funktionsdeklaration eine Exceptionspezifikation enthält (ausser noexcept(false)), müssen alle Deklaration dieser Funktion eine kompatible Exceptionspezifikation besitzen. Eine Diagnosemeldung ist nur vorgeschrieben, wenn der Fehler in einer einzigen Überstzungseinheit auftritt.
hustbaer schrieb:
Und... bekommst du von GCC mit -std=c++98 und ohne Exception-Spec wirklich einen Fehler oder bloss eine Warning?
mit -pedantic und #include <new> kann ich das nachvollziehen.
Es ist übrigens nicht erforderlich, diese Standardallokationsfunktion zusätzlich zu deklarieren; die Anpassung sollte sich daher auf eine einzige Stelle - dort wo die Funktion definiert wird - beschränken.
-
@camper
Hm OK.
Bleibt noch die Frage ob es der Implementierung erlaubt (bzw. sogar vorgeschrieben?) ist beim Operator new eine Exception-Specthrow(std::bad_alloc)
zu verwenden.
-
camper schrieb:
-pedantic und #include <new> kann ich das nachvollziehen.
Ich benutze in der Tat beides. Was mich wundert, denn nachdem ich dies gesehen habe, habe ich -pedanic aus der Kommandozeile entfernt, tatsächlich hat es nun beides ohne Fehlermeldungen verarbeitet. Wie kann es überhaupt sein, dass -pedantic Fehlermeldungen produziert? Laut Anleitung sollte das nicht so sein, vielmehr hätte ich das von -pedantic-errors erwartet (Außer fehlende Exception-Spezifikationen zählen als "forbidden extensions"). Und nein, ich verwende nicht -Werror.
-pedantic -Wall -Wextra -O0 -std=c++98
dyn.cpp: In function 'void* operator new(std::size_t)': dyn.cpp:139:33: error: declaration of 'void* operator new(std::size_t)' has a different exception specifier In file included from dyn.hpp:6:0, from dyn.cpp:1: c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.2/../../../../include/c++/4.7.2/new:93:7: error: from previous declaration 'void* operator new(std::size_t) throw (std::bad_alloc)'
Leicht übereifrige Genauigkeitsprüfung?