Dynarray Implementation
-
Und ich muss nochmal nachfragen:
Dynarray& operator=(Dynarray const& tmp) { Dynarray d(tmp); swap(d); return *this; }
Warum recyclest du hier keinen Speicher? Das ist trivial umsetzbar und macht in der Praxis einen Unterschied.
Solange der aktuelle allozierte Speicher ausreicht gibt es keinen Grund ihn freizugeben und neuen zu allozieren.
-
Ethon schrieb:
Solange der aktuelle allozierte Speicher ausreicht gibt es keinen Grund ihn freizugeben und neuen zu allozieren.
Doch. Man kann dann keine starke Exception-Garantie mehr geben.
-
Sone schrieb:
camper schrieb:
TyRoXx schrieb:
Der Destruktor ist implizit
noexcept(true)
.oh?
Ich glaube, TyRoXx verwechselt da den Dtor mit Deallokationsfunktionen.
Nicht unbedingt.
n3337 schrieb:
12.4 Destructors [class.dtor]
[...]
3 A declaration of a destructor that does not have an exception-specification is implicitly considered to have
the same exception-specification as an implicit declaration (15.4).Die Exceptionspezifikation eines implizit deklarierten Destruktors hängt von den Exceptionsspezifikationen der Funktionen ab, die von diesem aufgerufen würden, d.h. den Destruktoren der Member und der direkten oder virtuellen Basisklassen. Wenn keiner dieser Destruktoren direkt oder indirekt eine explizite Exceptionspezifikation erhält, läuft das somit tatsächlich im Allgemeinen auf eine Sepzifikation noexcept(true) hinaus.
Die Exceptionspezifikation ist mAn Teil der Schnittstelle und sollte somit nicht implizit von privaten Details der Klasse abhängen - deshalb halte ich eine explizite Angabe für sinnvoll. Der Standard macht es anders, man kann also durchaus auch andere Ansicht sein.
-
Lol, 5 Seiten Ratschläge und es funktioniert immer noch nicht.
Abgesehen von den Warnungen, wenn man deinen Code kompiliert (schonmal mit-Wall -Wextra
getestet?), es hat noch einige Bugs.Hier mal ein einfaches Testprogramm:
int instances = 0; void may_throw() { if (rand()%100 == 0) throw 0; } struct test { test() { ++instances; may_throw(); } test(test const&) { ++instances; may_throw(); } ~test() { --instances; } }; int main() { srand(0); try { Dynarray<test> d(1000); } catch (...) {} std::cout << instances << '\n'; }
Wenn Zeile 12 etwas abändert, dürfte der Fehler etwas klarer werden.
~test() { std::cout << --instances << '\n'; }
-
iksepschensaif schrieb:
Lol, 5 Seiten Ratschläge und es funktioniert immer noch nicht.
Abgesehen von den Warnungen, wenn man deinen Code kompiliert (schonmal mit-Wall -Wextra
getestet?), es hat noch einige Bugs.Hier mal ein einfaches Testprogramm:
int instances = 0; void may_throw() { if (rand()%100 == 0) throw 0; } struct test { test() { ++instances; may_throw(); } test(test const&) { ++instances; may_throw(); } ~test() { --instances; } }; int main() { srand(0); try { Dynarray<test> d(1000); } catch (...) {} std::cout << instances << '\n'; }
Wenn Zeile 12 etwas abändert, dürfte der Fehler etwas klarer werden.
~test() { std::cout << --instances << '\n'; }
Gefixed. Da war ein Missverständnis, ich dachte der Dtor wird dann nicht mehr aufgerufen ... jetzt ist das geklärt. (Und noch eine kleine Fallunterscheidung für den einen delegation Ctor
)
Vielen Dank :xmas1:
Edit: o.O eine bleibt immer übrig. Setz mich dran...
-
Ach, dein Beispiel ist doch bescheuert.
Man muss dasmay_throw
vor die Inkrementierung setzen, ist doch klar.Edit: Ihr seit ganz sicher, dass man bei einer Exception aus dem Dtor einfach nix aufräumen muss?
-
Ich hab sicherheitshalber mal hinzugefügt, dass wenn eine Exception im Dtor des zu zerstörenden Objektes fliegt (in
_destroyAllUntil
), einfach alles deallokiert wird und der Zeiger auf Null gesetzt wird (damit der Dtor übersprungen wird).
-
Sone schrieb:
Ich hab sicherheitshalber mal hinzugefügt, dass wenn eine Exception im Dtor des zu zerstörenden Objektes fliegt (in
_destroyAllUntil
), einfach alles deallokiert wird und der Zeiger auf Null gesetzt wird (damit der Dtor übersprungen wird).Dir fehlen Grundlagen. Lies mal das durch: http://home.ustc.edu.cn/~zixin/More%20Effective%20C++/MAGAZINE/SU_FRAME.HTM#destruct
-
iksepschensaif schrieb:
Sone schrieb:
Ich hab sicherheitshalber mal hinzugefügt, dass wenn eine Exception im Dtor des zu zerstörenden Objektes fliegt (in
_destroyAllUntil
), einfach alles deallokiert wird und der Zeiger auf Null gesetzt wird (damit der Dtor übersprungen wird).Dir fehlen Grundlagen. Lies mal das durch: http://home.ustc.edu.cn/~zixin/More%20Effective%20C++/MAGAZINE/SU_FRAME.HTM#destruct
Ja, aber wenn ich wirklich so tue als ob nichts passiert, und es gibt doch irgendeinen doofen Programmierer der einen Destruktor eine Exception emittieren lässt, dann ... leckt der ganze Speicher... was ist so falsch, einfach auf diesen Fall einzugehen?
Wieso muss man immer so tun als ob es keine schlechten User gibt?
Das ein Dtor nie eine Exception nach außen kommen lassen darf, ist mir schon klar.Edit: Btw: Geändert.
-
[...] with both of these is that they have fundamentally the same problem we just described for destroy! For example, consider the following code: ¤ Sutter, P145
T* p = new T[10]; delete[] p;
Looks like normal harmless C++, doesn't it? But have you ever wondered what new[] and delete[] do if a T destructor throws? Even if you have wondered, you can't know the answer for the simple reason that there is none: The standard says you get undefined behavior if a T destructor throws anywhere in this code, which means that any code that allocates or deallocates an array of objects whose destructors could throw can result in undefined behavior. [...]
Hast dus nicht gelesen? Undefinded bleibt undefined, egal ob man drauf reagiert. :xmas1:
-
ScottZhang schrieb:
Hast dus nicht gelesen? Undefinded bleibt undefined, egal ob man drauf reagiert. :xmas1:
Ach, es ist undefiniertes Verhalten? Na dann ^^
-
Sone schrieb:
Wieso muss man immer so tun als ob es keine schlechten User gibt?
Weil der Code, wenn du ihn auf schlechte User auslegst, selbst schlecht wird.
Natürlich kannst du die üblichen Fehlerquellen durch Compiletime-Mechanismen oder Assertions abfangen, die passieren ja auch guten Usern. Aber wenn du anfängst, selbstverständliche Dinge massiv zu verkomplizieren, nur weil jemand sie mit Absicht (oder grober Dummheit) falsch verwenden könnte, ist etwas nicht mehr gut. Solchen Leuten darf das Programm ruhig mit voller Wucht um die Ohren fliegen.
<:xmas2:>
-
glühnase schrieb:
Sone schrieb:
Wieso muss man immer so tun als ob es keine schlechten User gibt?
Weil der Code, wenn du ihn auf schlechte User auslegst, selbst schlecht wird.
Das ist mal ein Merksatz.
-
*push*
So, wie sieht's aus? Unschönheiten usw. muss es doch bestimmt noch geben. :xmas1:Edit: Ich setz' mich am besten mal an einen ausführlichen Test.
-
Sone schrieb:
Ich setz' mich am Besten mal an einen ausführlichen Test.
Am besten ohne allzu viele Rechtschreibfehler.
-
meinbester schrieb:
Sone schrieb:
Ich setz' mich am Besten mal an einen ausführlichen Test.
Am besten ohne allzu viele Rechtschreibfehler.
Willkommen im Internet.
Außerdem markiert der Duden das als eine rechtschreiblich schwierigige Verbindung
-
Warum gibt es keinen Standardkonstruktor?
-
TyRoXx schrieb:
Warum gibt es keinen Standardkonstruktor?
Weil
Dynarray
eine feste Größe hat.
Es macht keinen Sinn ein Dynarray zu erzeugen bevor man die Größe nicht kennt.
-
Sone schrieb:
TyRoXx schrieb:
Warum gibt es keinen Standardkonstruktor?
Weil
Dynarray
eine feste Größe hat.
Es macht keinen Sinn ein Dynarray zu erzeugen bevor man die Größe nicht kennt.Ich kenne die Größe doch: Null.
Eine Klasse ohne Standardkonstruktor ist unhandlich und es gibt hier keinen technischen Grund, keinen zu haben.
-
TyRoXx schrieb:
Sone schrieb:
TyRoXx schrieb:
Warum gibt es keinen Standardkonstruktor?
Weil
Dynarray
eine feste Größe hat.
Es macht keinen Sinn ein Dynarray zu erzeugen bevor man die Größe nicht kennt.Ich kenne die Größe doch: Null.
Eine Klasse ohne Standardkonstruktor ist unhandlich und es gibt hier keinen technischen Grund, keinen zu haben.Sehen wir uns mal an, was man mit einem Dynarray der Größe 0 überhaupt richtig tun kann.
- Mit einem anderen Dynarray tauschen - sinnlos, da wir gleich ein neues Objekt erzeugen und das andere moven könnten.
- Ein anderes Objekt zuweisen - könnten wir gleich im Ctor machen.
Nicht viel, oder?
Ich habe schon öfter mit dem Gedanken gespielt,Dynarrray
s der Größe Null zu verbieten.Um das ganze nochmal anders zu argumentieren, was schrieb ich am Anfang:
Sone schrieb:
Es ist eigentlich das schöne Äquivalent zu
int* array = new int[size];
bzw. mit VLAs
int array[size];
Du kannst kein echtes VL/Heap-Array ohne Größe erzeugen, entsprechend wäre das hier nicht sinnvoll.
Falls man jedoch auf einen Default-Konstruktor angewiesen ist, kann man es ja zur not binden.