C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Wie geht das mit der Kopie einer Instanz ?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
gustav04
Guest





PostPosted: Mon Apr 25, 2005 5:24 pm    Post subject: Wie geht das mit der Kopie einer Instanz ? Reply with quote



Hallo Leute,

ich hab mich irgendwie in folgendes Problem verrennt (ist wahrscheinlich
simple, aber im moment geht garnix mehr bei mir ... )

Also ich hab zwei Klassen:
Data = eine Klasse, welche Daten in einer Map speichert
Inifile = eine Klasse, die Konfigurationen aus einer (klassischen)
Inidatei einliest und über get-Methoden Values ausgegeben kann

Die Inifile Klasse verwendet daher die Data Klasse, um diverse Werte
nach ff. Muster zu speichern:

[Section]
Wert1 = Inhalt1
Wert2 = Inhalt2
....
....


Hier (vereinfacht) die Klassen-Header:

class Data
{
// nix aufregendes
// Konstruktor, Destruktor sowie
// ein Haufen set und get-Methoden und eine dump Methode

// gibt inhalt aus
void dump();
};



class Inifile
{
public:
// initializiert obj mit pfad zur ini-datei
// wenn datei vorhanden, dann wird inhalt eingelesen
// ansonsten neu angelegt
Inifile(const std::string &filename);

// bei änderung des inhaltes wird inidatei
// gespeichert und anschliessend obj zerstört
~Inifile ();

// get und set - methoden
Data* getData()
{ return m_configData;}

void setData( Data * node)
{ m_configData = node;}

...
...

// damit können Werte hinzugefügt werden nach dem Muster
// [Section]
// Feld1 = Inhalt1
// Feld2 = Inhalt2
void addValue(...);


private:
Data * m_configData;
};


Die ersten Testfälle funktionieren auch ganz gut. Aber wie ich so an den
Testfällen herumbastle, kam mir folgendes Szenario in den Kopf.

void main()
{
// inidatei eins existiert und wird eingelesen
Inifile *eins = new Inifile(pfad_zur_inidatei);

// inidatei zwei existiert noch nicht
Inifile *zwei = new Inifile(pfad_zur_anderen_inidatei);

// inidatei zwei wird mit daten von eins gefüllt
zwei->setData( eins->getData() );

// und jetzt schreib was neues in die inidatei zwei dazu
zwei->addValue("NEUE SECTION","FELD","INHALT");

...
...

// gib inhalt aus
zwei->dump();
eins->dump(); // !!!! hier steht plötzlich auch der Eintrag
}

Plötzlich war in beiden Dumps der neue Eintrag drinnen.

Irgendwie sollte ich doch mit einer Kopie der einen Data-Instanz
arbeiten und diese Kopie weiterreichen. Dort können dann die Daten
verändert werden. Oder zumindest im ersten Ansatz verhindern, dass Daten
ausserhalb der Instanz verändert werden. Daher hab ich vor und nach der
get-Methode ein const geschrieben, nur dann funktioniert die set-Methode
nicht.
Nur ... wie geht das jetzt? Oder geht das überhaupt irgendwie anders ?

Irgendwie hab ich einen ziemlich dicken Knopf im Hirn .... :-(

Weiss jemand Rat?

Danke und LGG

--
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
J.Sievers
Guest





PostPosted: Tue Apr 26, 2005 2:36 am    Post subject: Re: Wie geht das mit der Kopie einer Instanz ? Reply with quote




"gustav04" <gustav04 (AT) gmx (DOT) at> schrieb im Newsbeitrag
news:d4j7dn$tue$1 (AT) newsreader1 (DOT) utanet.at...
Quote:
Hallo Leute,

Plötzlich war in beiden Dumps der neue Eintrag drinnen.

Irgendwie sollte ich doch mit einer Kopie der einen Data-Instanz arbeiten
und diese Kopie weiterreichen. Dort können dann die Daten verändert
werden. Oder zumindest im ersten Ansatz verhindern, dass Daten ausserhalb
der Instanz verändert werden. Daher hab ich vor und nach der get-Methode
ein const geschrieben, nur dann funktioniert die set-Methode nicht.

Nun, wenn die Einträge dynamisch erzeugt wurden oder eben Pointer auf die
Einträge eg. sind und Du dann eine Instanz mit solchen Einträgen auf eine
andere Kopierst, dann werden (standartmassig) nur die Pointer kopiert. Ist
es ein Pointer auf eine Liste/String u.s.w., dann derefferenzieren nach dem
Kopieren beide Instanzen die selben Speicherbereiche ( Liste, Strings eg).
Noch spannender wird es wenn ein Objekt zerstört wird und die Liste mit
(delete/free) frei gibt und das/die anderen diese weiterhin verwenden.

Kurz um: Einen Copyoperator/Konstruktor schreiben, der Listen u.s.w.
physikalisch dupliziert.
Wenn sie aber immer identisch bleiben sollen, dann unbedingt Reffcounter
einführen.

j

--
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
Karl Heinz Buchegger
Guest





PostPosted: Tue Apr 26, 2005 9:58 am    Post subject: Re: Wie geht das mit der Kopie einer Instanz ? Reply with quote



gustav04 wrote:
Quote:
void main()
int main()


Quote:
{
// inidatei eins existiert und wird eingelesen
Inifile *eins = new Inifile(pfad_zur_inidatei);

// inidatei zwei existiert noch nicht
Inifile *zwei = new Inifile(pfad_zur_anderen_inidatei);

// inidatei zwei wird mit daten von eins gefüllt
zwei->setData( eins->getData() );

// und jetzt schreib was neues in die inidatei zwei dazu
zwei->addValue("NEUE SECTION","FELD","INHALT");

...
...

// gib inhalt aus
zwei->dump();
eins->dump(); // !!!! hier steht plötzlich auch der Eintrag
}

Plötzlich war in beiden Dumps der neue Eintrag drinnen.

Ist nicht weiter verwunderlich.

Im Klartext sagst Du ja hier:

zwei->setData( eins->getData() );

"Liebes Inifile 'zwei'. Ab sofort verwendest Du denselben Pointer zu den
Daten, den auch Inifile 'eins' benutzt."

Damit benutzen die beiden Inifiles dasselbe Data Objekt, da beide ja identische
Pointer darauf haben. Nebenbei bemerkt hast Du damit auch noch ein schoenes
Speicherloch produziert:

Das ganze faengt an mit:

Quote:
Inifile *eins = ....
(warum Du hier Pointer samt dynamischer Allokierung benuttz ist mir schleierhaft

aber was solls.)

eins
+---------+
Quote:
|
+---------+


Quote:
Inifile *eins = new Inifile(pfad_zur_inidatei);


eins
+---------+ +-----------------------+
Quote:
o----------------------->| Inifile Objekt |
+---------+ | |
m_configData: o------------------>+--------------------+
+-----------------------+ | eigentliche Daten |
|
|
+--------------------+



Quote:
Inifile *zwei = new Inifile(pfad_zur_anderen_inidatei);

eins
+---------+ +-----------------------+
Quote:
o----------------------->| Inifile Objekt |
+---------+ | |
m_configData:
o------------------>+----------------------------+

+-----------------------+ | eigentliche
Daten |
Quote:

aus |

pfad_zur_inidatei |


+----------------------------+

zwei
+---------+ +-----------------------+
Quote:
o----------------------->| Inifile Objekt |
+---------+ | |
m_configData:
o------------------>+----------------------------+

+-----------------------+ | eigentliche
Daten |
Quote:

aus |

pfad_zur_anderen_inidatei |


+----------------------------+

Quote:
zwei->setData( eins->getData() );
Hier wird '*eins' aufgefordert seinen Pointer auf die Daten rauszuruecken.

Dieser Pointer wird dann in '*zwei' reingestopft:


eins
+---------+ +-----------------------+
Quote:
o----------------------->| Inifile Objekt |
+---------+ | |
m_configData:
o------------------>+----------------------------+

+-----------------------+ +-------->| eigentliche
Daten |
Quote:
|
aus |
|
pfad_zur_inidatei |

+----------------------------+

zwei |

+---------+ +-----------------------+ |
Quote:
o----------------------->| Inifile Objekt | |
+---------+ | | |
m_configData: o---------+
+----------------------------+

+-----------------------+ | eigentliche
Daten |
Quote:

aus |

pfad_zur_anderen_inidatei |


+----------------------------+

Und wie man deutlich sieht, gibt es keinen Pointer mehr der auf die ursruenglichen Daten von *zwei
zeigt: Dieses Daten sind unerreichbar und sind daher ein Speicherleck.

Quote:

Irgendwie sollte ich doch mit einer Kopie der einen Data-Instanz
arbeiten und diese Kopie weiterreichen.

Diese Kopie wird aber nie erzeugt! Alles was Du tust ist ein paar Pointer umsetzen.
Hast Du in letzter Zeit zuviel Java programmiert? Das was Du hier zeigst ist ein
typischer Fehler den Java Umsteiger machen.

--
Karl Heinz Buchegger
[email]kbuchegg (AT) gascad (DOT) at[/email]

--
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
Karl Heinz Buchegger
Guest





PostPosted: Tue Apr 26, 2005 11:39 am    Post subject: Re: Wie geht das mit der Kopie einer Instanz ? Reply with quote

Karl Heinz Buchegger wrote:
Quote:


Tut mir leid.
Ich hab die Zeilen zu lang gemacht, und damit die ganze
Formatierung zerstoert. Hier nochmal, mit kuerzeren Zeilen:

Quote:
gustav04 wrote:
void main()
int main()

{
// inidatei eins existiert und wird eingelesen
Inifile *eins = new Inifile(pfad_zur_inidatei);

// inidatei zwei existiert noch nicht
Inifile *zwei = new Inifile(pfad_zur_anderen_inidatei);

// inidatei zwei wird mit daten von eins gefüllt
zwei->setData( eins->getData() );

// und jetzt schreib was neues in die inidatei zwei dazu
zwei->addValue("NEUE SECTION","FELD","INHALT");

...
...

// gib inhalt aus
zwei->dump();
eins->dump(); // !!!! hier steht plötzlich auch der Eintrag
}

Plötzlich war in beiden Dumps der neue Eintrag drinnen.

Ist nicht weiter verwunderlich.


Im Klartext sagst Du ja hier:

zwei->setData( eins->getData() );

"Liebes Inifile 'zwei'. Ab sofort verwendest Du denselben Pointer zu den
Daten, den auch Inifile 'eins' benutzt."

Damit benutzen die beiden Inifiles dasselbe Data Objekt, da beide ja identische
Pointer darauf haben. Nebenbei bemerkt hast Du damit auch noch ein schoenes
Speicherloch produziert:

Das ganze faengt an mit:

Quote:
Inifile *eins = ....
(warum Du hier Pointer samt dynamischer Allokierung benuttz ist mir schleierhaft

aber was solls.)

eins
+---------+
Quote:
|
+---------+


Quote:
Inifile *eins = new Inifile(pfad_zur_inidatei);

eins
+---------+ +-----------------------+
Quote:
o----------->| Inifile Objekt |
+---------+ | |
m_configData: o------------->+--------------------+
+-----------------------+ | eigentliche Daten |
|
|
+--------------------+


Quote:
Inifile *zwei = new Inifile(pfad_zur_anderen_inidatei);

eins
+---------+ +-----------------------+
Quote:
o---------->| Inifile Objekt |
+---------+ | |
m_configData: o-------->+----------------------------+
+-----------------------+ | eigentliche Daten |
aus |
pfad_zur_inidatei |
+----------------------------+


zwei
+---------+ +-----------------------+
Quote:
o---------->| Inifile Objekt |
+---------+ | |
m_configData: o------------>+----------------------------+
+-----------------------+ | eigentliche Daten |
aus |
pfad_zur_anderen_inidatei |
+----------------------------+


Quote:
zwei->setData( eins->getData() );
Hier wird '*eins' aufgefordert seinen Pointer auf die Daten rauszuruecken.

Dieser Pointer wird dann in '*zwei' reingestopft:

eins
+---------+ +-----------------------+
Quote:
o---------->| Inifile Objekt |
+---------+ | |
m_configData: o-------->+----------------------------+
+-----------------------+ | eigentliche Daten |

+>| aus |
Quote:
| pfad_zur_inidatei |
+----------------------------+

zwei |

+---------+ +-----------------------+ |
Quote:
o---------->| Inifile Objekt | |
+---------+ | | |
m_configData: o--------+ +----------------------------+
+-----------------------+ | eigentliche Daten |
aus |
pfad_zur_anderen_inidatei |
+----------------------------+


Und wie man deutlich sieht, gibt es keinen Pointer mehr der auf die ursruenglichen Daten von *zwei
zeigt: Dieses Daten sind unerreichbar und sind daher ein Speicherleck.

Quote:

Irgendwie sollte ich doch mit einer Kopie der einen Data-Instanz
arbeiten und diese Kopie weiterreichen.

Diese Kopie wird aber nie erzeugt! Alles was Du tust ist ein paar Pointer umsetzen.
Hast Du in letzter Zeit zuviel Java programmiert? Das was Du hier zeigst ist ein
typischer Fehler den Java Umsteiger machen.

--
Karl Heinz Buchegger
[email]kbuchegg (AT) gascad (DOT) at[/email]

--
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
gustav04
Guest





PostPosted: Tue Apr 26, 2005 8:10 pm    Post subject: Re: Wie geht das mit der Kopie einer Instanz ? Reply with quote

Hallo Newsgroup
Hi Karl,

also, wenn ich das richtig verstehe, gehört hier der klassische (und in
diesem Forum schon öfters anzutreffenden) Copyconstruktor eingebaut.

Super! Aber wieso ist mir das nicht gleich eingefallen ... das mit dem
Java stimmt insoweit, weil ich das Framework eigentlich unter J gebaut
hab und jetzt das ganze Ding unter C++ (quasi zur Übung) nachbauen
wollte ...

jedenfalls: vielen Dank für die gute Erklärung, der Knoten in meinem
Hirn hat sich vorerst mal gelöst ;-)


Lg G



Karl Heinz Buchegger wrote:
Quote:
Karl Heinz Buchegger wrote:


Tut mir leid.
Ich hab die Zeilen zu lang gemacht, und damit die ganze
Formatierung zerstoert. Hier nochmal, mit kuerzeren Zeilen:


gustav04 wrote:

void main()

int main()


{
// inidatei eins existiert und wird eingelesen
Inifile *eins = new Inifile(pfad_zur_inidatei);

// inidatei zwei existiert noch nicht
Inifile *zwei = new Inifile(pfad_zur_anderen_inidatei);

// inidatei zwei wird mit daten von eins gefüllt
zwei->setData( eins->getData() );

// und jetzt schreib was neues in die inidatei zwei dazu
zwei->addValue("NEUE SECTION","FELD","INHALT");

...
...

// gib inhalt aus
zwei->dump();
eins->dump(); // !!!! hier steht plötzlich auch der Eintrag
}

Plötzlich war in beiden Dumps der neue Eintrag drinnen.

Ist nicht weiter verwunderlich.

Im Klartext sagst Du ja hier:

zwei->setData( eins->getData() );

"Liebes Inifile 'zwei'. Ab sofort verwendest Du denselben Pointer zu den
Daten, den auch Inifile 'eins' benutzt."

Damit benutzen die beiden Inifiles dasselbe Data Objekt, da beide ja identische
Pointer darauf haben. Nebenbei bemerkt hast Du damit auch noch ein schoenes
Speicherloch produziert:

Das ganze faengt an mit:


Inifile *eins = ....

(warum Du hier Pointer samt dynamischer Allokierung benuttz ist mir schleierhaft
aber was solls.)

eins
+---------+
| |
+---------+


Inifile *eins = new Inifile(pfad_zur_inidatei);


eins
+---------+ +-----------------------+
| o----------->| Inifile Objekt |
+---------+ | |
| m_configData: o------------->+--------------------+
+-----------------------+ | eigentliche Daten |
| |
| |
+--------------------+


Inifile *zwei = new Inifile(pfad_zur_anderen_inidatei);


eins
+---------+ +-----------------------+
| o---------->| Inifile Objekt |
+---------+ | |
| m_configData: o-------->+----------------------------+
+-----------------------+ | eigentliche Daten |
| aus |
| pfad_zur_inidatei |
+----------------------------+

zwei
+---------+ +-----------------------+
| o---------->| Inifile Objekt |
+---------+ | |
| m_configData: o------------>+----------------------------+
+-----------------------+ | eigentliche Daten |
| aus |
| pfad_zur_anderen_inidatei |
+----------------------------+


zwei->setData( eins->getData() );

Hier wird '*eins' aufgefordert seinen Pointer auf die Daten rauszuruecken.
Dieser Pointer wird dann in '*zwei' reingestopft:

eins
+---------+ +-----------------------+
| o---------->| Inifile Objekt |
+---------+ | |
| m_configData: o-------->+----------------------------+
+-----------------------+ | eigentliche Daten |
+>| aus |
| | pfad_zur_inidatei |
| +----------------------------+
|
zwei |
+---------+ +-----------------------+ |
| o---------->| Inifile Objekt | |
+---------+ | | |
| m_configData: o--------+ +----------------------------+
+-----------------------+ | eigentliche Daten |
| aus |
| pfad_zur_anderen_inidatei |
+----------------------------+

Und wie man deutlich sieht, gibt es keinen Pointer mehr der auf die ursruenglichen Daten von *zwei
zeigt: Dieses Daten sind unerreichbar und sind daher ein Speicherleck.


Irgendwie sollte ich doch mit einer Kopie der einen Data-Instanz
arbeiten und diese Kopie weiterreichen.


Diese Kopie wird aber nie erzeugt! Alles was Du tust ist ein paar Pointer umsetzen.
Hast Du in letzter Zeit zuviel Java programmiert? Das was Du hier zeigst ist ein
typischer Fehler den Java Umsteiger machen.

--
Karl Heinz Buchegger
[email]kbuchegg (AT) gascad (DOT) at[/email]


--
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
Karl Heinz Buchegger
Guest





PostPosted: Wed Apr 27, 2005 8:15 am    Post subject: Re: Wie geht das mit der Kopie einer Instanz ? Reply with quote

gustav04 wrote:
Quote:

Hallo Newsgroup
Hi Karl,

also, wenn ich das richtig verstehe, gehört hier der klassische (und in
diesem Forum schon öfters anzutreffenden) Copyconstruktor eingebaut.

Aehm. Ja und Nein.
Das Problem liegt ganz woanders.
Das Problem ist das Du zu leichtfertig mit Pointer umgehst. Eine Klasse
gibt nicht einfach so mir nichts, dir nichts einen Pointer auf seine
internen Daten raus bzw. akzeptiert so nebenbei einen Pointer auf Daten
die es verwenden soll.

Dein Problem ist ein Designproblem. Solange Du das nicht behebst, nuetzt
dir ein Copykonstruktor genau gar nichts, da er niemals zum Zug kommt.
Irgendwann muessen die Daten tatsaechlich kopiert werden und nicht nur
ein Pointer neu besetzt werden. (Das Kopieren koennte man auch mit ausgefuchsteren
Mitteln wie Reference Counting und Copy on Write beheben, aber das moechte ich
Dir jetzt erst mal nicht zumuten).

Ich schlage mal folgende Aenderung vor:

zunaechst mal werde alle Pointer und damit die dynamischen Allokierung
los! Du brauchst sie nicht wirklich. Insbesondere hat ein Inifile ja wohl
*immer* einen Data Member. Der Rest ergibt sich dann daraus fast schon von
alleine.

--
Karl Heinz Buchegger
[email]kbuchegg (AT) gascad (DOT) at[/email]

--
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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.