Absturz bei Klassentemplates
-
Hey,
ich habe folgendes Problem: Ich habe ein Klassentemplate, welches einen Graphen darstellen soll. Wenn ich in dem Template allerdings zu große Werte übergebe, stürzt das Programm aufgrund eines Stack-Overflows ab!
#pragma once #include <iostream> #include <string> using namespace std; template <class TV, int maxNodes> class Digraph { private: class Vertex { public: Vertex() { // Konstruktor indegree = outdegree = ord = 0; visited = false; living = false; value = 0; } TV value; // Markierung int indegree; // Eingangsgrad int outdegree; // Ausgangsgrad int ord; // Ordnungszahl des Knotens bool visited; // Knoten-"besucht"-Marke bool living; // Knoten existiert }; double noArc; int numvertices; // Anzahl der Knoten eines Digraphen int numarcs; // Anzahl der Kanten eines Digraphen Vertex vertex[maxNodes]; // repräsentiert Knoten des Digraphen double arc[maxNodes][maxNodes]; // repräsentiert bewertete Kanten des Digraphen (-1=keine Kante) ARC = EDGE public: Digraph(){ // Digraphen generieren noArc = -1; for (int i=0;i<maxNodes;i++) //Adajenz-Matrix füllen for (int j=0;j<maxNodes;j++) arc[i][j]=noArc; }und hier halt noch meine Test-Main, wo ich das Objekt erstelle:
int main(){ Digraph<int, 500> graphy; return 0; }Fehler:
Eine Ausnahme (erste Chance) bei 0x00411947 in Aufgabe 12.exe: 0xC00000FD: Stack overflow.
Unbehandelte Ausnahme bei 0x00411947 in Aufgabe 12.exe: 0xC00000FD: Stack overflow.Mich wundert es, dass es hier schon zu einem StackOverflow kommt. Ich denke mal, dass es an dem double arc[maxNodes][maxNodes] liegt. Aber bei 500*500 Integer Werten komme ich bei 4 Byte pro Int auf 1Mb. Scheitert es echt daran??
Das ganze ist eigentlich nicht sehr schlimm. Ich brauche nicht mehr als 50, damit stürzt das Programm nicht ab! Aber wenn ich dann damit weiterprogrammiere bekomme ich beim ifstream und ofstream immer folgenden Fehler, obwohl ich keine dll's benutze.
Windows hat einen Haltepunkt in Navi.exe ausgelöst.
Dies kann auf eine Beschädigung des Heaps zurückzuführen sein und weist auf ein Problem in Navi.exe oder in einer der geladenen DLLs hin.
Davor habe ich eine Liste benutzt und da ging die gleiche Methode (mit of und ifstream). Hier mal ein kleiner Auszug, die bindatei wurde vorher mit einem String initialisiert (als Klassenmethode). Der Teil mit Kommentar zeigt an wo der Debugger rausspringt.
void Navigationssystem::bin_lesen(){ char tmp[100] = {0}; ifstream quelle; // CRASH quelle.open(bindatei.c_str(), ios::binary|ios::in); ...Da aber die Methode vorher einwandfrei funktioniert hat, denke ich liegt es an dem oben genannten Problem! Oder es kann es vielleicht daran liegen, dass ich eine selbstgeschriebene Klasse in der Template benutze? (Digraph<Ort, 10> graphy;)
Ich benutze Visual C++ 2005 und benutze einen relativ neuen Laptop mit >2Gb Ram
Falls ihr noch mehr Code braucht, sagt bescheid.
-
ok dann wollen wir mal

unter windows ist der stack normalerweise ca. 1MB groß. -> batsch deshalb stürtzt
er ab. verusch entweder ein ynamisches array oder nimm std::vector:std::vector<std::vector<double> > arc; // im ctor classname() : noArc(-1), arc(max, std::vector<double>(max, noArc))wobei ich mir bei letzerem nicht sicher bin in welcher reihenfolge das initialisisert wird
du kannst ruhig klassen in templates definieren, gar kein problem und durchaus üblich
teste mal ons damit immernoch abstürtzt
-
tippgeber schrieb:
wobei ich mir bei letzerem nicht sicher bin in welcher reihenfolge das initialisisert wird
von links nach rechts bzw oben nach unten, wenn man auf je eine zeile schreibt...
foo::foo() : a(0), b(a) {}das ist also iO
bb
-
unskilled schrieb:
tippgeber schrieb:
wobei ich mir bei letzerem nicht sicher bin in welcher reihenfolge das initialisisert wird
von links nach rechts bzw oben nach unten, wenn man auf je eine zeile schreibt...
foo::foo() : a(0), b(a) {}das ist also iO
bb
Nope. Es spielt keine Rolle, in welcher Reihenfolge das in der Initialisierungsliste steht, sondern in der Deklaration in der Klasse. (das sieht man oft ganz fiese Fehler erzeugen. ;))
-
drakon schrieb:
unskilled schrieb:
tippgeber schrieb:
wobei ich mir bei letzerem nicht sicher bin in welcher reihenfolge das initialisisert wird
von links nach rechts bzw oben nach unten, wenn man auf je eine zeile schreibt...
foo::foo() : a(0), b(a) {}das ist also iO
bb
Nope. Es spielt keine Rolle, in welcher Reihenfolge das in der Initialisierungsliste steht, sondern in der Deklaration in der Klasse. (das sieht man oft ganz fiese Fehler erzeugen. ;))
OO
Sicher? Was sollte das für nen Grund haben?
Hab auch gerad nix im Standard dazu gefunden -.-bb
-
ISO/IEC 14882 12.6.2/5 schrieb:
5 Initialization shall proceed in the following order:
[...]
— Then, nonstatic data members shall be initialized in the order they were declared in the class definition
(again regardless of the order of the mem-initializers).
-
danke
-
Hat das nenn Sinn, dass die das so unlogisch gemacht haben?
-
oho schrieb:
Hat das nenn Sinn, dass die das so unlogisch gemacht haben?
Das hat einen Sinn, und das ist alles andere als unlogisch. Gesetzt den Fall, die Reihenfolge in der Initialisierungsliste wäre entscheidend. Dann könnte man zwei Konstruktoren haben mit verschiedener Initialisierungsreihenfolge. Beim Zerstören eines Objektes sollte aber die Reihenfolge der Zerstörung der Member umgekehrt zur Initialisierung sein. Je nachdem welcher Konstruktor aufgerufen wurde, müsste also im Destruktor ein anderer Ablauf erfolgen. Dazu müsste wiederum für jedes einzelne Objekt mitgeloggt werden, in welcher Reihenfolge die einzelnen Member initialisiert wurden. Das würde einen nicht akzeptablen Overhead erzeugen.
Bei der Initialisierung in der Reihenfolge der Memberdeklaration kommt dagegen noch ein anderer Vorteil hinzu: Meistens werden die einzelnen Member in der Reihenfolge der Deklaration im Speicher abgelegt. Beim Initialisieren in derselben Reihenfolge kann dann der zum Objekt gehörige Speicher "von vorne nach hinten" initialisiert werden, ohne dass wild darin hin- und hergehüpft werden muss.
-
noch n punkt, warum es gut ist dass man mit dem neuen standard etwas von diesen initialisierungslisten weg kommt.
-
pumuckl schrieb:
Beim Zerstören eines Objektes sollte aber die Reihenfolge der Zerstörung der Member umgekehrt zur Initialisierung sein.
Wieso muss das der Fall sein?
@1punkt:
aber wenn die Initialisierung der einzelnen Member voneinander abhängig ist, siehts auch schon nich mehr so gut aus mit der neuen Art der Initialisierung - und man ist wieder(immernoch) auf die Init-Liste angewiesen... Abhängig nacheinander klingt nämlich auch immer nach abhängig von Parametern...bb
-
unskilled schrieb:
pumuckl schrieb:
Beim Zerstören eines Objektes sollte aber die Reihenfolge der Zerstörung der Member umgekehrt zur Initialisierung sein.
Wieso muss das der Fall sein?
Ich denke mal, dass dir ein wenig Code mehr sagt, als ein langer Text.

class B { public: int i; B () : i ( 2 ) {} ~B () { i = 0; } }; class A { B& b_; public: A ( B& b ) : b_ ( b ) { std::cout << b_.i << std::endl; } ~A () { std::cout << b_.i << std::endl; } }; class foo { B b; A a; public: foo () : a ( b ) { } ~foo () { } }; int main () { foo f; }Was wäre hier, wenn a und b in foo nicht in umgekehrter Reihenfolge zerstört werden würde?
-
unskilled schrieb:
@1punkt:
aber wenn die Initialisierung der einzelnen Member voneinander abhängig ist, siehts auch schon nich mehr so gut aus mit der neuen Art der Initialisierung - und man ist wieder(immernoch) auf die Init-Liste angewiesen... Abhängig nacheinander klingt nämlich auch immer nach abhängig von Parametern...Versteh nicht was du meinst. Die InitListe bringt doch nichts bei Abhängigkeiten, da sowieso nach Deklarationsreihen folge init. wird. Oder hab ich drakon falsch verstanden?
-
Ich denke er meinte, das, wenn man das machen will, was ich im obigen Beispiel gemacht habe und man zuerst a ( b ) und dann b () macht. Dann sieht das verwirrend aus und kann eine falsche Annahme verursachen.