Hallo,
ich habe ein Problem. Und zwar ist es mir nicht möglich innerhalb von
Methoden einer Klasse speicher zu allokieren und diesen sowohl
Klassenvariablenpointern oder extern deklarierten Pointern zuzuweisen.
Weder new() noch malloc() noch vector::insert() funktionieren. Alle
bringen den Fehler bad_alloc.
Angaben: C++, Visual Studio 2005.
Hat jemand damit Erfahrung und möglicherweise einen guten Tip, woran es
liegen könnte.
Vielen Dank! jowi
Hallo,
ich muß gestehen, daß ich nicht 100%ig verstehe, was mit der Zuweisung
an Klassenpointervariablen gemeint ist. Spätestens dann, wenn eine
Zuweisung an extern deklarierte Pointer nicht möglich ist, würde mir das
aber zu denken geben.
Wurde vielleicht versucht, zu viel Speicher zu alloziieren (maximale
Heapgröße in Projekteinstellungen, ...)? Das kann auch passieren, wenn
der Heap groß genug, aber stark fragmentiert ist und kein Block
ausreichender Größe mehr frei ist. Oder ungültiger Parameter für zu
alloziierende Größe.
Und seit wann wirft malloc(), was eine reine C-Funktion ist, eine
C++-Exception, es sei denn, man installiert einen eigenen Handler für
fehlgeschlagene Speicherallokation und wirft die selber?
Ansonsten solltest Du mal den Beispielcode für Dein Problem minimieren,
möglichst wenige Zeilen, und hier posten, denn "freihändig" kann man zu
dem Problem wenig sagen.
Tschüß, Matthias
jowi schrieb:> // Füge neuen Leerstring ein, an den später über vector::push_back()> // einzelne chars angefügt werden sollen
häh?
dann hast du einen vector mit strings
[0] = ""
[1] = "a"
[2] = "4"
> --> funktionier, wenn ich alles> // in der main schreibe.
macht aber nicht das, was du wahrscheinlich willst.
> // Hier löst die interne Alloc-Funktion ein bad_alloc aus
das sollte in der Tat nicht passieren.
ist dein rechner vollgemüllt?
linkst du gegen komische runtimes?
jowi schrieb:> void klasse::testfunktion(char * temp) {> // Nachfolgendes funktioniert beides nicht, obwohl es sich um eine> //Klassenvariable handelt --> bad_alloc> temp = new char(10);> temp = (char*) malloc(10*sizeof(char));> }
was genau erwartest du, was in dieser funktion passiert und was du hast,
wenn die funktion zurückkehrt?
Es macht überhaupt keinen Sinn einem Input-Pointer neuen Speicher
zuzuweisen
> temp = new char(10);
was soll das eigentlich erzeugen?
das folgende malloc lässt vermuten, dass du
temp = new char[10];
meinst.
Tip 1:
starte den Rechner neu, existiert das Speicherproblem noch, installiere
die eine konsistente Toolchain
Tip 2:
Kaufe dir ein C++ Buch und erarbeite dir die Sprache.
Hallo,
Ok. Entschuldige, dass ich in der Eile runde mit eckigen Klammern
vertauscht habe. Und ja, jeder fängt mal an und ein C++ Buch habe ich,
das hilft mir bei diesem Problem aber auch nicht weiter.
1
// Funktion splittet einzelne Protokoll-Zeilen anhand eine Delimiters auf.
2
// Leerzeichen werden hierbei ignoriert. Für jeden Part der Zeile wird in
introw=0;// amount of array-rows with rowWidth chars each
8
9
// Füge ersten Leerstring hinzu, an den die eingelesenen Chars
10
// angehängt werden können
11
writeBuf->insert(writeBuf->begin(),"");
12
13
while(readBuf[i]!='\r'){
14
if(readBuf[i]!=' '||delim==' '){
15
if(readBuf[i]!=delim){
16
(*writeBuf)[row].push_back(readBuf[i]);
17
}
18
else{
19
// Füge neuen Leerstring in Vektor ein
20
writeBuf->insert(writeBuf->end(),"");
21
row++;
22
}
23
}
24
i++;// Increment sign-counter
25
}
26
27
return0;
28
}
Die oben aufgeführte Methode erhält von extern ein Delimiter-Zeichen,
einen char-Pointer auf ein Array, das die zu verarbeitenden Daten
enthält, sowie einen Zeiger auf einen Vektor, in der die aufgesplittete
Zeile gespeichert werden soll.
Den Vektor habe ich extern deklariert (in der main) und die
Speicherallokation ist deswegen nötig, weil diese beim Hinzufügen eines
neuen Strings automatisch aufgerufen wird.
Viele Grüße, jowi
so macht das ganze schon mehr sinn
jowi schrieb:> Den Vektor habe ich extern deklariert (in der main) und die> Speicherallokation ist deswegen nötig, weil diese beim Hinzufügen eines> neuen Strings automatisch aufgerufen wird.
und beim insert oder push-back wirft er exceptions?
irgendwas scheint mit deiner Buildumgebung nicht zu stimmen.
Tip:
writeBuf->insert(writeBuf->end(),"");
da kannst du auch
writeBuf->push_back("");
schreiben
Tip:
in c++ benutzt man lieber referenzen anstatt von Pointern.
Dann kannst du dir auch die dereferenzierungen sparen:
... vector<string>& writeBuf...
.
.
.
writeBuf.push_back("");
.
.
.
writeBuf[row].push_back(readBuf[i]);
.
.
.
writeBuf.push_back("");
Hallo jowi,
wie Vlad schon angedeutet hat, ist Dein Beispiel 2 sinnlos, da der
Rückgabewert der Speicherallokation nicht zurückgeliefert wird.
Erst einmal ist es eine gute Idee, die Fehlermeldungen zu analysieren.
Liefert Dir bad_alloc::what() bzw. bzw. strerror(errno) irgendwas
sinnvolles?
Hast Du die Projekteinstellungen (Heapgröße) kontrolliert?
Funktionieren andere Projekte, die dynamisch Speicher alloziieren, in
der gleichen Umgebung, z. B. beim Compiler mitgelieferte Beispiele?
Compilierst Du mit Debugging und linkst Du mit den Debug-Bibliotheken?
Das liefert u. U. Fehlermeldungen, wo die "normale" Version einfach
nicht funktioniert.
Verwendest Du Multithreading und linkst versehentlich mit den
Single-Threaded-Bibliotheken?
Führst Du an anderen Stellen wilde Pointeroperationen durch, die evtl.
den Heap beschädigen?
Ein Microsoft-typischer Fehler ist, in einer DLL Speicher zuzuweisen und
anderswo freizugeben oder umgekehrt - unter UNIX geht das normalerweise
gut.
Abgesehen davon würde ich Dir empfehlen, für den vektor<string> ein
typedef zu machen, den Vektor nicht dynamisch zu alloziieren und dann
per Referenzparameter an Verarbeitungsfunktionen zu übergeben. Das wird
Dir beim aktuellen Problem vermutlich nichts helfen, ist aber sauberer
und weniger fehleranfällig.
Tschüß, Matthias
Hallo und vielen Dank erstmal!
Ganz schön viel Input, den ich mal abarbeiten werde.
Kurze Infos noch:
bad_alloc wird bereits von dem ersten insert geworfen. Kopiere ich den
gesamten Code in die main, in der ich auch die zu übergebenden Parameter
deklariere, funktioniert der gesamte Code!
Deklarationen:
1
vector<string>*writeBuf=newvector<string>;
2
char*readBuf="Beispiel zum testen\r\n";
Komisch ist halt, dass ich innerhalb der Klassenmethoden in keiner Weise
Speicher allokieren (oder alloziieren?) kann. Es scheitert immer und ich
bekomme oben genannten Null-Zeiger oder ein bad_alloc zurück.
Das ist doch sehr komisch, oder? Selbst beim Allokieren von Speicher für
Pointervariablen der Klasse (z.B. einfach char *) treten diese Fehler
auf. Hierfür werden ja nichtmal Zeiger von extern übergeben!
PS: Nach dem Neustart des Rechners sofort beim ersten Durchlauf
dieselben Probleme, es kann also nicht an einem zugemüllten Rechner
liegen.
Viele Grüße, jowi
Kannst du mal ein minimales, aber komplettes Programm posten, das den
Fehler zeigt? Dann könnte man eher sagen, ob dein Programm einen Fehler
hat oder es doch an irgendwas anderem liegt.
Anbei ein gesamtes Beispielprogramm:
Die Klassendefinition wird hierbei nicht mitgeführt, da die Funktion
keine Variablen der Klasse bearbeitet. Ich weiß, dann könnte man die
Funktion auch gleich extern deklarieren, aber ich hätte das gern alles
zusammen. Außerdem funktioniert das reservieren von Speicher ja generell
nicht innerhalb von Klassen-Methoden, auch wenn ich damit
Pointervariablen der Klasse bearbeite.
Die Konsolenparameter sind derzeit irrelevant. Diese sind dauerhaft
unter den Projekt-Eigenschaften/Debug-Optionen gesetzt.
Main-Funktion:
1
int_tmain(intargc,_TCHAR*argv[]){
2
vector<string>*writeBuf=newvector<string>;
3
char*readBuf=NULL;// = "Beispiel zum testen\r\n";
4
5
bspklasseclient(argv[1]);// Initialisierung eines Objektes. Für unsere Problem-Betrachtung uninteressant!
introw=0;// amount of array-rows with rowWidth chars each
5
6
// Füge ersten Leerstring hinzu, an den die eingelesenen Chars
7
// angehängt werden können
8
writeBuf->insert(writeBuf->begin(),"");
9
10
while(readBuf[i]!='\r'){
11
if(readBuf[i]!=' '||delim==' '){
12
if(readBuf[i]!=delim){
13
(*writeBuf)[row].push_back(readBuf[i]);
14
}
15
else{
16
// Füge neuen Leerstring in Vektor ein
17
writeBuf->insert(writeBuf->end(),"");
18
row++;
19
}
20
}
21
i++;// Increment sign-counter
22
}
23
24
return0;
25
}
Mehr ist es ja gar nicht.
Ich hoffe, ihr könnt mir helfen.
PS: Ich kompiliere als Debug; eine Toolchain (soweit ich weiß:
verschiedene Entwicklungsprogramme anstelle von Vstudio?) will ich nicht
verwenden, da ich das später auf ein WinCE portieren will und hierzu den
Platformbuilder benötige! Ich weiß, es kann sein, dass WinCE einige
Bibliotheken evtl nicht unterstützt. Das interessiert mich vorerst aber
nicht. Die Gesamtfunktionalität soll erstmals gegeben und umgesetzt
sein.
Grüße, jowi
Hallo Jowi,
zu Deinem Posting von 13:47 und dem Problem des Crashs in Methoden:
Mir ist da gerade eine ganz dumme Idee gekommen: Könnte es sein, daß Du
vergißt, das Objekt, auf das Du zugreifst, zu initialisieren
(new-Operator bzw. statischer Konstruktoraufruf) oder Member-Variablen
im Konstruktor zu initialisieren?
Tschüß, Matthias
also bei dem code muss es krachen, da dein readBuf NULL ist.
ansonsten geht der Code.
zeig doch mal bitte alles (Klassendefinition, Konstruktor).
möglicherweise zerstört irgendwas vor dem split-Funktionsaufruf den Heap
Oh entschuldige, beim Testen war readBuf mit dem auskommentierten Text
initialisiert.
Muss man eigentlich alle Klassenvariablen und Pointer im Konstruktor
initialisieren? Also point = NULL, ints = 0?
Eigentlich solange ich nicht auf die durch Pointer verwiesenen
Speicherstellen zugreife, sollte ja nichts passieren. Oder?
Ich initialisiere sie trotzdem mal vollständig.
Grüße, jowi
also ich gebs auf.
da du nicht mit einem kompletten Minimalbeispiel rausrückst ist dir
nicht zu helfen.
jetzt kommst du auf einmal scheinbar völlig zusammenhangslos mit c-files
und wüstestem Pointercode.
wenn du VS benutzt, kann man höchstwahrscheinlich von einer konsistenten
Toolchain ausgehen. Der Fehler liegt also zu 99% in dem Code, den du uns
nicht gezeigt hast.
Der Code im letzten Beispiel stammt nicht von mir, in dem endet das
Debuggen.
Ich möchte den gesamten Code nicht offenbaren, da es sich hierbei um
einen Teil meiner Bachelorarbeit in einer Firma handelt und ich bei
dieser eine Geheimhaltungsverpflichtung unterschrieben habe. Das will
und traue ich mich einfach nicht. Ich hoffe, ihr könnt das
nachvollziehen.
Ja, ich hatte während dem Studium mal C++ aber im Schmalspurverfahren
und nicht sonderlich tief. Der Begriff des Vektoren im Zusammenhang mit
C++ war mir z.B. bis gestern unbekannt.
Kannst du mir Tips geben, wo ich noch schauen könnte?
Die Definition meiner Klasse scheint mir korrekt:
1
classname{
2
private:
3
// Variablen- und Pointer-Deklarationen sowie private Methoden
4
5
public:
6
// Deklaration von Konstruktor, Destruktor und sonstigen Methoden
7
// unter anderem auch splitline()
8
};
Im Konstruktor habe ich alles initialisiert. Pointer = NULL; INTs = 0;
Ja, irgendwo muss es dennoch an meinem Code liegen, da stimme ich dir
zu. Alles innerhalb der Main-Funktion programmiert, funktioniert ja. Nur
die Speicherallokierung innerhalb der Methoden der Klasse geht schief.
Komisch ist auch, dass in manchen Methoden die Allokierung schonmal
funktionierte. Ich habe aber nichts verstellt/geändert?!?
Ich räume meinen Code mal auf, alles was nicht rein muss, kommt weg.
Vielleicht finde ich ja den Fehler.
Ich würde mich dennoch über Tips und Ideen freuen.
Vielen Dank dir/euch!
Grüße, jowi
jowi schrieb:> Ich möchte den gesamten Code nicht offenbaren,
Dann reduziere den auf ein compilierbares Beispiel, das Dein Problem
enthält.
Funktioniert das Beispiel, hat Deine Reduktion die Fehlerursache
beseitigt - und Du hast einen Anhaltspunkt, wo das Problem tatsächlich
liegt.
Mit Codefetzchen und Schnipselchen wirst Du hier aber auf keinen grünen
Zweig kommen.
Ok. Ich werde ein Beispiel in einem neuen Projekt programmieren, welches
den Fehler reproduziert und euch das hier einstellen. Es wäre nett, wenn
ihr dann nochmal einen Blick darauf werfen könntet.
Bis dahin und vielen Dank an alle!
Grüße, jowi
>Muss man eigentlich alle Klassenvariablen und Pointer im Konstruktor>initialisieren? Also point = NULL, ints = 0?>>Eigentlich solange ich nicht auf die durch Pointer verwiesenen>Speicherstellen zugreife, sollte ja nichts passieren. Oder?>>Ich initialisiere sie trotzdem mal vollständig.
Erst einmal, Klassenvariablen sind Variablen, die nicht einer Instanz
einer Klasse, sondern der Klasse selbst gehören und von allen Instanzen
der Klasse geteilt werden (Deklaration mit static ...). Du meinst
wahrscheinlich Instanz- oder Objektvariablen. Man sagt im
objektorientierten Jargon auch Member-Variablen.
Es ist dringend zu empfehlen, immer alles vollständig zu initialisieren.
Es kann zwar wirklich nichts passieren, solange Du nicht drauf
zugreifst, aber das ist guter Stil. Machst Du es nicht, so schaffst Du
künstlich eine mögliche spätere Fehlerquelle - und das können Fehler
sein, die sehr schwer zu analysieren sind, z. B. funktioniert in
Entwicklungsversion/im Debugger, aber nicht in Release-Version,
funktioniert sporadisch nicht, funktioniert auf Plattform A, aber nicht
auf Plattform B usw.
Du mußt sie übrigens nicht unbedingt im Body des Konstruktors
initialisieren:
1
MeineKlasse() : point(NULL), ins(0) {}
tut's auch. Das sind Konstruktoraufrufe, in diesem Fall der
Standard-Konstruktoren. Braucht ein Konstruktor Parameter, dann muß man
es sogar so machen.
Hallo alle miteinander!
Nochmals vielen Dank für eure Hilfe! Ich hab mir vieles zu Herzen
genommen und mit großer Freude gelesen. Tips sind immer gut, da kann man
nur lernen. Ich verwende jetzt auch meist Referenzparameter anstelle von
Pointern. Es ist wahr, damit lässt sichs meist einfacher arbeiten und
der Code bleibt/wirkt übersichtlicher. :-)
Da ihr meintet, dass der Code ansonsten funktionstüchtig aussieht, habe
ich nochmal ein neues, leeres Projekt erstellt, alle Einstellungen in
den Projekteigenschaften selber vorgenommen und meine einzelnen
Codeblöcke übernommen und teilweise verschönert und siehe da, plötzlich
funktioniert es.
Dafür ging zwar nochmal gut ein Abend und ein Morgen drauf, aber dafür
funktioniert's. Ich kann euch jetzt leider nicht genau sagen, wo der
Fehler lag. Entweder im Code oder in dem vorkonfigurierten Visual Studio
Projekt.
Auf jeden Fall danke nochmals! Habt nen schönen Tag.
Grüße, Jowi
jowi schrieb:> funktioniert's. Ich kann euch jetzt leider nicht genau sagen, wo der> Fehler lag. Entweder im Code oder in dem vorkonfigurierten Visual Studio> Projekt.
Er lag mit ziemlicher Sicherheit in deinem Code.
Irgendwo hast du in den nicht gezeigten Programmteilen die
Runtime-Umgebung zerschossen. Das könnte zb ein Array-Zugriff Out of
Bounds gewesen sein (das ist der häufigste Fall).
Hallo Karl Heinz,
> Er lag mit ziemlicher Sicherheit in deinem Code.> Irgendwo hast du in den nicht gezeigten Programmteilen die> Runtime-Umgebung zerschossen. Das könnte zb ein Array-Zugriff Out of> Bounds gewesen sein (das ist der häufigste Fall).
Das ist recht wahrscheinlich, ich halte es aber ebenfalls für möglich,
daß es tatsächlich eine zerschossene Projektdatei war - das habe ich bei
dem Compiler auch schon erlebt, Winzigweich eben ;-)) .
Tschüß, Matthias