 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Johannes Huber Guest
|
Posted: Wed Oct 06, 2004 3:08 pm Post subject: Templateschachtelung |
|
|
Hallo Leute,
ich habe in Problem mit der Speicherverwaltung in folgendem Programm:
#include <iostream>
template <class Data>
class CMyArray
{
public:
int m_nSize;
Data* m_pData;
CMyArray() { m_nSize = 0; m_pData = NULL; }
~CMyArray() { if(m_pData) delete m_pData; }
void SetSize(int NewSize);
};
template <class Data>
void CMyArray<Data>::SetSize(int NewSize)
{
Data *NewMem = new Data[NewSize];
Data *pNewMem = NewMem, *pOldMem = m_pData;
int Min = m_nSize < NewSize ? m_nSize : NewSize;
for(;pNewMem
if(m_pData) delete m_pData;
m_pData = NewMem;
m_nSize = NewSize;
}
int main(int nArgs, char** Arg)
{
CMyArray< CMyArray test;
test.SetSize(1);
return 0;
}
Ich erhalte eine Access Violation im inneren Destruktor also in
CMyArray<int>::~CMyArray<int>, weshalb ist mir nicht klar.
Anscheinend ist mit meinem Pointer auf das Innere Objekt etwas nicht in
Ordnung, denn die A.V. kommt genauer gesagt aus _CrtIsValidHeapPointer.
Hat einer von euch eine Idee, woran das liegen könnte? Hängt das vielleicht
mit dem verschachtelten Template zusammen?
Vielen Dank
Hannes
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Markus Schaaf Guest
|
Posted: Wed Oct 06, 2004 3:41 pm Post subject: Re: Templateschachtelung |
|
|
"Johannes Huber" <huber (AT) fom (DOT) fgan.de> schrieb:
| Quote: | template
class CMyArray
{
public:
int m_nSize;
Data* m_pData;
CMyArray() { m_nSize = 0; m_pData = NULL; }
~CMyArray() { if(m_pData) delete m_pData; }
void SetSize(int NewSize);
};
|
Klassischer Anfängerfehler: Wenn Du einen D'tor brauchst, brauchst Du auch
Copy-C'tor und Copy-Assignment.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Wed Oct 06, 2004 3:51 pm Post subject: Re: Templateschachtelung |
|
|
"Johannes Huber" <huber (AT) fom (DOT) fgan.de> writes:
| Quote: | #include <iostream
|
Unnötig.
| Quote: | template
class CMyArray
{
public:
int m_nSize;
Data* m_pData;
|
Public Datenmembers?
| Quote: | CMyArray() { m_nSize = 0; m_pData = NULL; }
|
Für die Initialiserung der Datenmembers gibt's die
Memberinitialisierungsliste.
| Quote: | ~CMyArray() { if(m_pData) delete m_pData; }
|
Dieser Check ist unnötig.
| Quote: | void SetSize(int NewSize);
};
|
Es fehlen da mindestens Kopierkonstruktor und Kopierzuweisungsoperator.
Die vom Compiler generierten tun nicht das richtige.
| Quote: | template
void CMyArray
{
Data *NewMem = new Data[NewSize];
Data *pNewMem = NewMem, *pOldMem = m_pData;
int Min = m_nSize < NewSize ? m_nSize : NewSize;
for(;pNewMem
|
Da gibt's mehrere Probleme:
1) Du rufst den Kopierzuweisungsoperator auf. Das produziert den Absturz, wenn
der (wie bei CMyArray
Und scheinbar nicht für alle Elemente des neuen Data-Arrays; mir ist das
zu kompliziert, als dass ich es durchschauen könnte.
Was spricht gegen
int const minsize(std::min(m_nSize,NewSize));
std::copy(m_pData,m_pData+minsize,pNewMem);
2) Wenn eine der Kopier-Zuweisungen schiefgeht, verlierst Du Resourcen, weil
delete [] NeMem nicht aufgerufen wird.
| Quote: | if(m_pData) delete m_pData;
|
Wieder ein unnötiger Check.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
dietmar_kuehl@yahoo.com Guest
|
Posted: Wed Oct 06, 2004 3:58 pm Post subject: Re: Templateschachtelung |
|
|
Markus Schaaf wrote:
| Quote: | "Johannes Huber" <huber (AT) fom (DOT) fgan.de> schrieb:
template <class Data
class CMyArray
{
public:
int m_nSize;
Data* m_pData;
CMyArray() { m_nSize = 0; m_pData = NULL; }
~CMyArray() { if(m_pData) delete m_pData; }
void SetSize(int NewSize);
};
Klassischer Anfängerfehler: Wenn Du einen D'tor brauchst, brauchst
Du auch
Copy-C'tor und Copy-Assignment.
|
Die Aussage ist zwar korrekt, aber nicht die Ursache für das Problem:
es wird in dem inneren Array in dem Beispielprogramm kein Speicher
angelegt und die Nullen werden durch den generierten Copy-Konstruktor
bzw. die generierte Assignment-Funktion korrekt kopiert. Was mir
aufgefallen ist, ist dass 'delete m_pData' verwendet wird, was falsch
ist:
'm_pData' ist ein Array-Objek und muss mit 'delete[] m_pData'
freigegeben
werden. ... und der Test 'if (m_pData)' ist ueberfluessig.
--
<http://www.contendix.com> - Software Development & Consulting
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Markus Schaaf Guest
|
Posted: Wed Oct 06, 2004 4:11 pm Post subject: Re: Templateschachtelung |
|
|
<dietmar_kuehl (AT) yahoo (DOT) com> schrieb:
| Quote: | es wird in dem inneren Array in dem Beispielprogramm kein Speicher
angelegt und die Nullen werden durch den generierten Copy-Konstruktor
bzw. die generierte Assignment-Funktion korrekt kopiert. Was mir
aufgefallen ist, ist dass 'delete m_pData' verwendet wird, was falsch
ist:
|
Interessanterweise wird im inneren Array auch nicht kopiert, weil
ja nur der Default-C'tor läuft und die alte Größe 0 war. Wenn der
gepostete Code stimmt, sollte der innere D'tor gar nichts machen.
Irgendwas ist faul ...
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Johannes Huber Guest
|
Posted: Thu Oct 07, 2004 7:47 am Post subject: Re: Templateschachtelung |
|
|
<dietmar_kuehl (AT) yahoo (DOT) com> schrieb im Newsbeitrag
news:1097078313.581164.233350 (AT) h37g2000oda (DOT) googlegroups.com...
| Quote: | Markus Schaaf wrote:
"Johannes Huber" <huber (AT) fom (DOT) fgan.de> schrieb:
template
class CMyArray
{
public:
int m_nSize;
Data* m_pData;
CMyArray() { m_nSize = 0; m_pData = NULL; }
~CMyArray() { if(m_pData) delete m_pData; }
void SetSize(int NewSize);
};
Klassischer Anfängerfehler: Wenn Du einen D'tor brauchst, brauchst
Du auch
Copy-C'tor und Copy-Assignment.
Die Aussage ist zwar korrekt, aber nicht die Ursache für das Problem:
es wird in dem inneren Array in dem Beispielprogramm kein Speicher
angelegt und die Nullen werden durch den generierten Copy-Konstruktor
bzw. die generierte Assignment-Funktion korrekt kopiert. Was mir
aufgefallen ist, ist dass 'delete m_pData' verwendet wird, was falsch
ist:
'm_pData' ist ein Array-Objek und muss mit 'delete[] m_pData'
freigegeben
werden. ... und der Test 'if (m_pData)' ist ueberfluessig.
|
Hallo,
vielen Dank, die Sache mit dem delete[] war's. Super, danke.
Weshalb weiß der Compiler eigentlich nicht selber, was er da löschen muß,
also weshalb gibt es überhaupt so etwas wie delete[]?
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Dietmar Kuehl Guest
|
Posted: Thu Oct 07, 2004 4:18 pm Post subject: Re: Templateschachtelung |
|
|
"Johannes Huber" <huber (AT) fom (DOT) fgan.de> wrote:
| Quote: | vielen Dank, die Sache mit dem delete[] war's.
|
Das ueberrascht mich allerdings... Das ist das erste Mal, dass ich von
einem realen Problem hoere, das auf der falschen Verwendung von 'delete'
anstatt 'delete[]' beruht!
| Quote: | Weshalb weiß der Compiler eigentlich nicht selber, was er da löschen muß,
also weshalb gibt es überhaupt so etwas wie delete[]?
|
Das kommt partiell noch aus den Zeiten, als jedes Byte gespart wurde: um
Platz fuer die Information zu haben, dass es ein Array-Objekt ist, braeuchte
man irgendwo mindestens ein extra Bit, was sich ganz schnell zu einem Byte
auswaechst, weil es nirgendwo Platz gibt. Das wiederum fuehrt ganz schnell
zu weiteren Bytes fuer Alignment, was ggf. bereits eine Verdoppelung des
Platzbedarfs bedeuten wuerde.
.... und heutzutage ist das schon deshalb kein Problem, weil man ja
eigentlich keine Arrays allokiert, sondern 'std::vector<T>' verwendet.
Wer Arrays allokiert sollte halt besser wissen was er tut und es sonst
bleiben lassen
--
<mailto:dietmar_kuehl (AT) yahoo (DOT) com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Fri Oct 08, 2004 9:55 am Post subject: Re: Templateschachtelung |
|
|
Dietmar Kuehl wrote:
| Quote: | "Johannes Huber" <huber (AT) fom (DOT) fgan.de> wrote:
vielen Dank, die Sache mit dem delete[] war's.
Das ueberrascht mich allerdings... Das ist das erste Mal, dass ich von
einem realen Problem hoere, das auf der falschen Verwendung von 'delete'
anstatt 'delete[]' beruht!
|
Ist doch prima. Endlich können wir auf einen Präzedenzfall hinweisen, der
zeigt, daß der Fehler nicht nur akademischer Natur ist :-)
| Quote: | Weshalb weiß der Compiler eigentlich nicht selber, was er da löschen muß,
also weshalb gibt es überhaupt so etwas wie delete[]?
Das kommt partiell noch aus den Zeiten, als jedes Byte gespart wurde: um
Platz fuer die Information zu haben, dass es ein Array-Objekt ist,
braeuchte man irgendwo mindestens ein extra Bit, was sich ganz schnell zu
einem Byte auswaechst, weil es nirgendwo Platz gibt. Das wiederum fuehrt
ganz schnell zu weiteren Bytes fuer Alignment, was ggf. bereits eine
Verdoppelung des Platzbedarfs bedeuten wuerde.
|
Die Aussage hab ich schon öfters gehört, kann sie aber nicht nachvollziehen.
Der Compiler weiß doch, wie groß das zu löschende Objekt ist, und zur
Laufzeit ist dem Programm normalerweise auch die Größe des belegten
Speicherblocks bekannt. D.h. es müßte auch automatisch herausfinden können,
daß es nicht ein einzelnes Objekt, sondern ein ganzes Array ist.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Christoph Rabel Guest
|
Posted: Fri Oct 08, 2004 10:08 am Post subject: Re: Templateschachtelung |
|
|
Rolf Magnus wrote:
| Quote: | Dietmar Kuehl wrote:
Das ueberrascht mich allerdings... Das ist das erste Mal, dass ich von
einem realen Problem hoere, das auf der falschen Verwendung von 'delete'
anstatt 'delete[]' beruht!
Ist doch prima. Endlich können wir auf einen Präzedenzfall hinweisen, der
zeigt, daß der Fehler nicht nur akademischer Natur ist
|
Naja, z.B. mit dem gcc zeigt folgendes Programm das relativ klar:
#include <iostream>
struct A
{ ~A() { std::cout << "A destroyedn"; } };
int main()
{
A* a = new A[2];
delete a;
}
Ausgabe:
A destroyed
Sollte ja eigentlich zweimal erscheinen.
mfg
Christoph
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Fri Oct 08, 2004 10:29 am Post subject: Re: Templateschachtelung |
|
|
Christoph Rabel wrote:
| Quote: | Naja, z.B. mit dem gcc zeigt folgendes Programm das relativ klar:
#include
struct A
{ ~A() { std::cout << "A destroyedn"; } };
int main()
{
A* a = new A[2];
delete a;
}
Ausgabe:
A destroyed
Sollte ja eigentlich zweimal erscheinen.
|
Wow. Da hab ich die ganze Zeit gedacht, mit allen üblichen Compilern würde
es auch bei dem falschen "delete a;" beide Elemente zerstören, und jetzt
ist es ausgerechnet bei dem von mir momentan ausschließlich benutzen gcc
nicht der Fall. Ich hab's ehrlich gesagt nie ausprobiert.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Heinz Saathoff Guest
|
Posted: Fri Oct 08, 2004 12:44 pm Post subject: Re: Templateschachtelung |
|
|
Rolf Magnus schrieb...
| Quote: |
Wow. Da hab ich die ganze Zeit gedacht, mit allen üblichen Compilern würde
es auch bei dem falschen "delete a;" beide Elemente zerstören, und jetzt
ist es ausgerechnet bei dem von mir momentan ausschließlich benutzen gcc
nicht der Fall. Ich hab's ehrlich gesagt nie ausprobiert.
|
Gleiches hier mit dem Digital-Mars Compiler. Der Speicher wird wohl
freigegeben, aber die Destruktoren werden nicht für jedes Element
aufgerufen.
Beim DMC kann ich allerdings bei PODs delete oder delete[] schreiben.
Das dies beim gcc nicht geht, ist tatsächlich überraschend. Vielleicht
kann jemand mit Zugriff auf den gcc dieses Verhalten mal verifizieren?
- Heinz
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Torsten Robitzki Guest
|
Posted: Fri Oct 08, 2004 5:31 pm Post subject: Re: Templateschachtelung |
|
|
Rolf Magnus wrote:
| Quote: | Die Aussage hab ich schon öfters gehört, kann sie aber nicht nachvollziehen.
Der Compiler weiß doch, wie groß das zu löschende Objekt ist, und zur
Laufzeit ist dem Programm normalerweise auch die Größe des belegten
Speicherblocks bekannt. D.h. es müßte auch automatisch herausfinden können,
daß es nicht ein einzelnes Objekt, sondern ein ganzes Array ist.
|
genau das ist doch das Argument. Wenn der Compiler weis, wie groß der
frei zu gebende Speicherbereich ist, wieso sollte man diese Information
noch einmal zur Laufzeit bereit halten?
mfg Torsten
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Thomas Dorner Guest
|
Posted: Fri Oct 08, 2004 9:45 pm Post subject: Re: Templateschachtelung |
|
|
HS>Das dies beim gcc nicht geht, ist tatsächlich überraschend. Vielleicht
HS>kann jemand mit Zugriff auf den gcc dieses Verhalten mal verifizieren?
Bestätigt:
~> g++ --version
g++ (GCC) 3.3.3 (SuSE Linux)
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
~> g++ -o zzz zzz.cpp && zzz
A destroyed
~>
Viele Grüße, Thomas
--
From-Adresse wird nicht genutzt, Reply-To Adresse gilt nur 4 Wochen!
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Malte Starostik Guest
|
Posted: Wed Oct 13, 2004 8:53 pm Post subject: Re: Templateschachtelung |
|
|
Heinz Saathoff schrieb:
| Quote: | Rolf Magnus schrieb...
Wow. Da hab ich die ganze Zeit gedacht, mit allen üblichen Compilern würde
es auch bei dem falschen "delete a;" beide Elemente zerstören, und jetzt
ist es ausgerechnet bei dem von mir momentan ausschließlich benutzen gcc
nicht der Fall. Ich hab's ehrlich gesagt nie ausprobiert.
Gleiches hier mit dem Digital-Mars Compiler. Der Speicher wird wohl
freigegeben, aber die Destruktoren werden nicht für jedes Element
aufgerufen.
|
Ich kann nicht kommentieren, ob DMC den Speicher wirklich korrekt
freigibt, garantiert ist dies jedenfalls nicht:
struct A{ /*...*/ };
int main()
{
A* a1 = new A; // 1
A* a2 = new A[ 100 ]; // 2
delete a1; // 3
#ifdef FALSCH
delete a2; // 4a
#else
delete[] a2; // 4b
#endif
}
Zeile 1 alloziert sizeof( A ) Bytes, initialisiert dort ein Objekt vom
Typ A, auf das im Folgenden a1 zeigt.
was in Zeile 2 genau passiert, damit Zeile 4b korrekt die dtors aller
100 As aufruft, hängt vom jeweiligen Compiler ab.
Die zwei grundlegenden Varianten sind (evtl. nötiges Padding mal
unterschlagen):
a) es werden 100 * sizeof( A ) + sizeof( size_t ) Bytes alloziert, die
Anzahl der Elemente wird in den ersten sizeof( size_t ) Bytes des
Bereichs abgelegt, dahinter 100 As initialisiert und a2 wird so
initialisiert, daß es auf das erste dieser As zeigt.
b) es werden 100 * sizeof( A ) Bytes alloziert, dort 100 As
initialisiert und a2 wiederum so initialisiert, daß es auf das erste
dieser As zeigt. Zusätzlich wird in einer anderweitig verwalteten
Tabelle die Adresse des Arrays der Anzahl der Elemente zugeordnet.
Zeile 3 ruft erwartungsgemäß den dtor des A auf, auf das a1 zeigt und
gibt anschließend die sizeof( A ) Bytes wieder Frei.
Zeile 4a ruft den dtor des A auf, auf das a2 zeigt (also nur des ersten)
und versucht, den Speicherbereich wieder freizugeben.
Letzteres funktioniert nur dann, wenn Zeile 2 die Methode b) verwendet
hat. Der entsprechende Eintrag in der Zuordnungstabelle für die
Arraygröße wird nicht entfernt. Im Falle a) wird der Speicherverwaltung
ein Zeiger (a2) übergeben, der von der ihr nie alloziert wurde
(alloziert wurde reinterpret_cast< size_t* >( a2 ) - 1)
In jedem Fall ist der Aufruf also unabhängig von den fehlenden
dtor-Aufrufen falsch, da entweder der Speicher nicht korrekt freigegeben
oder der Eintrag in der Zuordnung Arrayadresse => Arraygröße nicht
entfernt wird.
Zeile 4b behandelt dies dagegen korrekt, da es die Anzahl der Elemente
wieder von dort ausliest, wo Zeile 2 sie abgelegt hat und entsprechend
entweder beim Deallozieren den an die Speicherverwaltung übergebenen
Zeiger nach unten korrigiert oder den Eintrag aus der Zuordnungstabelle
entfernt.
| Quote: | Beim DMC kann ich allerdings bei PODs delete oder delete[] schreiben.
Das dies beim gcc nicht geht, ist tatsächlich überraschend. Vielleicht
kann jemand mit Zugriff auf den gcc dieses Verhalten mal verifizieren?
|
bei PODs fällt das Problem mit den fehlenden dtor-Aufrufen schonmal weg.
Angenommen, DMC verwendet die Zuordnungsmethode b), wird auch der
Speicher freigegeben, die entsprechende Tabelle enthält danach jedoch
einen ungültigen Eintrag (im Endeffekt auch wieder ein Leak). Denkbar
wäre hier auch, daß bei PODs keinerlei Information über die Anzahl der
Elemente gespeichert wird, da die Speicherverwaltung bereits weiß, wie
groß der Bereich ist und die Anzahl nicht weiter benötigt wird. Dann
wäre tatsächlich nichts zu bemängeln, es sei denn, man verwendet eigene
new/delete-Operatoren (s.u.)
Nun könnte theoretisch der eingebaute delete-Operator beide Varianten
vereinen (benögt dann aber irgendwo die Information, ob es sich um ein
Array handelt oder nicht). Dies würde jedoch die Flexibilität eigener
Implementierungen der new- und delete-Operatoren einschränken, da sich
dann auch noch der Anwendungsentwickler darum kümmern müßte, die
Arrayverwaltung erneut zu implementieren.
Diese Operatoren lassen sich aber z.B. prima dazu verwenden, in einer
Debug-Version auf korrekte Übereinstimmung von new und delete resp.
new[] und delete[] zu prüfen.
Schön' Gruß,
Malte
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|