# C++ Speicherverwaltung



## Illuvatar (26. Jul 2011)

Moin,

ich muss zur Zeit für die Uni in C++ programmieren. Was mir dabei Probleme macht, ist - natürlich - die Speicherverwaltung. Ich würde das gerne irgendwie sauber (OOP! auch wenn der Prof da nicht viel davon hält... ), halbwegs performant und ohne Hilfe von Frameworks (weil es eben Uni-Abgaben sind) hinkriegen.
Meine Frage ist: Gibt es irgendwelche sinnvollen Faustregeln, wie man programmieren sollte - insbesondere, zu welchem Zeitpunkt man Speicher wieder freigeben sollte?
(Ich weiß doch, dass es hier auch einige C++ Veteranen gibt )

Mal kurz mein konkretes Problem: Ich verwende eher kleinere, immutable Klassen und versuche nach Möglichkeit 
	
	
	
	





```
new
```
 zu vermeiden, damit die Objekte automatisch wieder gelöscht werden. Ich habe allerdings eine Klasse "WaveFunction", die mit einem potentiell sehr großen 
	
	
	
	





```
std::vector<complex<double>>
```
 hantiert. Diesen will ich nicht dauernd in der Gegend rumkopieren. Hab ich also einen Pointer drausgemacht, und dann kam zunächst (gekürzt) folgendes raus:

```
#include <vector>
using std::vector;
#include "cmp.h"

class WaveFunction {
private:
	vector<cmp> const * const values;
	WaveFunction(vector<cmp> const *values_)
		: values(values_) {}

public:
	static WaveFunction create(int N);
	virtual ~WaveFunction() {
		delete values; // <---- ???
	}
};

WaveFunction WaveFunction::create(int N) {
	vector<cmp>* values = new vector<cmp> (N);
	// werte berechnen...
	return WaveFunction(values);
}
```

Naja, das ist jetzt halt offensichtlich problematisch: Wenn irgendwo mal ein WaveFunction-Objekt by-value übergeben wird, und das eine der Objekte dann wieder gelöscht wird, wird gleich der Vektor mitgelöscht... Aber wie mache ich das denn sonst?


----------



## Gastredner (26. Jul 2011)

Ich bin jetzt *kein* C++-Veteran, aber: wird bei Call by Value nicht u. U. der Copy-Constructor oder eine andere Methode/Funktion aufgerufen? In diesem Falle könnte man über ein sehr einfaches Reference-Counting verhindern, dass der Pointer auf den Vector freigegeben wird, solange es noch Referenzen auf das Objekt gibt.
Wobei das natürlich ein potentieller Fall für Memory Leaks wäre, sollten irgendwo ungenutzte Referenzen rumhängen.:noe:


----------



## muckelzwerg (26. Jul 2011)

So aus dem Handgelenk hätte ich jetzt was von "Boost" gesagt. Vor allem, wenn es bei Deinem UniProjekt eigentlich um was anderes geht.
Wenn Du das nicht benutzen darfst/willst/kannst, dann findest Du darin aber vielleicht ein paar Tips zur Implementierung von Smartpointern.
Boost C++ Libraries
C/C++ Forum :: Schlaue Zeiger - Boost Smart Pointer


----------



## Marco13 (26. Jul 2011)

Auch ich bin kein "C++-Veteran". Früher habe ich ein bißchen mehr mit C++ gemacht, aber nichts wo sich derartige Fragen ernsthaft stellen würden (oder es war mir nicht bewußt). Immer, wenn ich später dann wieder mal was mit C++ gemacht habe, habe ich gemerkt, dass ich den "Java-Stil" dort hin übernehme. D.h.: ALLES sind Pointer. In diesem Fall wäre das Problem ja relativ leicht ... erledigt, wenn "create" auch einen (mit new allokierten) Pointer auf eine WaveFunction zurückgeben würde. Genaugenommen ist das Problem nur an den Aufrufer weitergereicht worden, aber vielleicht reicht das ja schon  

Tatsächlich versuchen die meisten Leute, mit Boost (Smart Pointer) das ganze handhabbar zu machen. (Meiner Ansicht nach läuft das darauf raus, dass man hunderte Hilfklassen und Bibliotheken einbindet, um mit C++ zumindest _ansatzweise_ so bequem programmieren zu können, wie mit Java von vornherein, aber... (woh-ho... "Bashing-Alarm"  Ich halt jetzt lieber die Klappe )


----------



## Illuvatar (26. Jul 2011)

@Gastredner: Das mit dem Copy-Constructor könnte sein, da hab ich gar nicht mehr dran gedacht. Das wäre eventuell die einfachste Möglichkeit.

@Boost: Ja das Stichwort Boost fällt da oft  Ich seh das halt irgendwie genau wie Marco13:


> Meiner Ansicht nach läuft das darauf raus, dass man hunderte Hilfklassen und Bibliotheken einbindet, um mit C++ zumindest ansatzweise so bequem programmieren zu können, wie mit Java von vornherein


Vielleicht bin ich da zu sehr auf der Schiene, dass ich denke man muss eine Sprache doch verwenden können ohne diese hunderte Bibliotheken. Aber gut, wenn es jetzt ein größeres Projekt wäre würde ich das vermutlich trotzdem benutzen. Nur kommt hier eben dazu, dass das eine wöchentliche Abgabe ist, mein Tutor hatte auch kaum Vorkenntnisse in C++ und die "Musterlösungen" sind 2-3 Seiten C-Code in eine Datei und manchmal sogar in eine Funktion geklatscht. Da weiß ich auch nicht, wie viel ich den Leuten zumuten kann...

@Marco13: Mit "alles sind Pointer" hab ich auch angefangen... bis ich dann gemerkt hab, dass man ja  theoretisch alles was man mit "new" erstellt, auch wieder selbst mit "delete" löschen muss (oder?). Dann hab ich deshalb für lokale Variablen angefangen zu mischen, dann gemerkt dass ich genau die Probleme von oben krieg, und dann Pointer so gut wie es geht weggelassen...
Abgesehen davon denk ich mir - auch wenn ich weiß, dass niemand anderes als ich die Klasse je benutzen wird  - dass es ja nicht "idiotensicher" wäre wenn ich bei create einen Pointer zurückgebe. Der Benutzer der Klasse könnte ja auf die Idee kommen, die Variable zu dereferenzieren und dann by value zu übergeben.


----------



## muckelzwerg (26. Jul 2011)

Ich mag Boost eigentlich auch nicht so sehr. Ich hab ein komisches Gefühl dabei, wenn ich extra eine Bibliothek "brauche", um solche grundlegenden Funktionen bereitzustellen.
Auf der anderen Seite ist das irgendwann wieder schlichtweg s*****egal. Da kommt es dann darauf an, dass die Funktionalität gebraucht wird und man bei weitem nicht die Zeit hat, um es selbst genausogut oder gar besser zu machen.
Gerade wenn man bei dem Projekt eigentlich was ganz anderes als Kernthema hat, muss man als Java-Profi aufpassen, sich nicht in zu viel Softwaretechnik zu verirren.

Wenn die Programme wirklich nur 2-3 Seiten lang sind, dann scheint mir das schon ziemlicher Overkill, was Du da anstrebst. Kommt das vielleicht vom Wechsel Java nach C++? Da erwartet man vielleicht doch etwas zu viel "Framework" und stellt an den Code andere Ansprüche was potentielle Fehlbenutzung etc. angeht.
Bei einem so kleinen Programm hätte ich gesagt "Valgrind und gut is", falls Du unter Linux arbeitest. Ansonsten benutzt Du unter Windows doch bestimmt eine IDE mit entsprechenden Tools.

Das ist jetzt nicht böse gemeint, aber wenn Du bei so einem Programm Smartpointer usw. wirklich BRAUCHST und sie nicht nur deshalb verwenden willst, weil Du Dich aus Javasicht sonst nicht wohl fühlst, solltest Du vielleicht etwas mehr mit C++ üben.
Natürlich werden Smartpointer etc. irgendwann wichtig, aber im Moment klingt diese Wochenaufgabe für mich nicht nach dem typischen Anwendungsfall dafür.


----------



## Marco13 (26. Jul 2011)

Illuvatar hat gesagt.:


> dass man ja  theoretisch alles was man mit "new" erstellt, auch wieder selbst mit "delete" löschen muss (oder?).



Ja, muss man - nicht nur theoretisch  Ehrlich gesagt ist mir auch schleierhaft, wie man diese Verantwortlichkeiten sauber in einem größeren Programm umsetzen soll (ohne smart pointer & Co). Das implizierte Kopieren von Objekten bei der Rückgabe (ohne Pointer) ist mir auch suspekt (niemand weiß, ob jemand von den Dingen, die in so einem vector liegen, den Zuweisungsoperator so überladen hatt, dass er MineSweeper startet :autsch: ). Man kann da höchstens versuchen, möglichst viel über 'const references' abzubilden, aber mit den Implikationen von "const oder nicht const" kann man IMHO auch schnell in die Hölle kommen...
Vermutlich ist dort Übung und Erfahrung noch wichtiger, als bei anderen Sprachen... :rtfm:


----------



## KuhTee (26. Jul 2011)

Illuvatar hat gesagt.:


> Wenn irgendwo mal ein WaveFunction-Objekt by-value übergeben wird, ...


Wie wärs mit referenzen? Die funktionieren in c++ ein bischen anders als die referenzen in java (welche eher mit den C++ pointer zu vergleichen wären).

Da dir die feinheiten von c++ allerdings offenbar noch fremd sind, solltest du vielleicht nicht versuchen, die mega-elegante lösung zu finden, sondern eine die "zu fuss" korrekte ergebnisse liefert?

Meine erfahrung ist, dass c++ neulinge, die von java kommen, sich grundsätzlich verrennen, wenn es darum geht objekte hin und her zu reichen. Dann wird kopiert, wo man referenzen verwenden sollte, und ratzfatz knallt es oder man wundert sich, warum das übergebene objekt sich anders verhält als erwartet.

Das ganze funktioniert eben anders und man sollte gar nicht erst versuchen, java memoryhandling paradigmen auf c++ zu übertragen (zumindest nicht wenn man nicht eine entsprechende bibliothek wie boost verwendet). Also entweder low level mit new und passendem delete, oder aber man setzt sich hin und lernt wie das in c++ mit referenzen, pointern und co funktioniert.

In deinem kurzen code beispiel zB wäre könnte der "vector<cmp>" eine referenz statt einem pointer sein. Das hängt aber ganz davon ab, was du machen willst.


----------



## Gast2 (26. Jul 2011)

Moin, auch schon etwas her aber,

alles was mit *new* erzeugt wird, landet auf dem Heap - muss also mittels *delete* wieder vernichtet werden ... beachte aber bitte das *malloc* & *free* mit *new* & *delete* nicht gemischt werden dürfen (ja das geht) ... alles andere landet auf dem Stack - und das wird ungültig (bzw. zerstört), wenn es den Sichtbarkeitsbereich verlässt

daher



Marco13 hat gesagt.:


> Das implizierte Kopieren von Objekten bei der Rückgabe (ohne Pointer) ist mir auch suspekt




```
Foo foo();
return &foo; // Kündigung wert
```



> (niemand weiß, ob jemand von den Dingen, die in so einem vector liegen, den Zuweisungsoperator so überladen hatt, dass er MineSweeper startet :autsch: )


der Mann gehört gevierteilt



KuhTee hat gesagt.:


> Wie wärs mit referenzen?


das löst nicht das eigentliche Problem ... IMO gehören Referenzen auf den Müll - ich persönlich finde den Quellcode dann nicht mehr eindeutig lesbar (foo.bar() bzw. foo->bar())


----------



## Marco13 (26. Jul 2011)

Das mit der Kündigung ist nicht ganz klar. Das kachelt ja beim ersten Durchlauf ohenhin ab. Es ging nur darum, dass man ja als "Daumenregel" sagen könnte, dass man _wenn möglich_ Referenzen verwenden sollte, und nur _wenn nötig_ Pointer. Aber Referenzen haben auch ein paar Stolperfallen. (Ich finde (nach langer Zeit mit Java) dass C++ wegen solcher Dinge einfach nur "unbequem" ist....)

Das mit dem MineSweeper sollte auch nur ein Beispiel sein: Ggf. kann so eine Zuweisung recht komplex sein. Und wenn man irgendwo 

```
class X {
    vector<Complex> v;
    void set(vector<Complex> arg) { v = arg; }
...
```
bzw

```
vector<Complex> v = somewhere.get();
```
schreibt, wird dort AFAIK standardmäßig jedes mal eine Tiefe Kopie (!?!) erstellt. Das kann teuer werden, wenn man nicht aufpasst.


----------



## ice-breaker (26. Jul 2011)

eventuell in deinem Objekt einen ganz billigen Reference-Counter implementieren?
Bei jeder Referenz den Zähler erhöhen, beim dereferenzieren das Gegenteil und bei 0 das Objekt löschen?
Dürfte wahrscheinlich in 20-30 Zeilen Code implementierbar sein.


----------



## Marco13 (26. Jul 2011)

Hm. Wie sollte das gehen?

```
WaveDingens *w = new WaveDingens();
WaveDingens *w0 = w;
WaveDingens *w1 = w;
{
    WaveDingens *w2 = w;
    WaveDingens *w3 = w;
}
WaveDingens *w4 = w;
WaveDingens *w5 = w;

// Welchen Wert hat der Reference Counter hier?
```
?! 
Wenn man sich den Boost SmartPointer mal ansieht, erkennt man, dass das nicht sooo einfach ist...


----------



## Gast2 (26. Jul 2011)

Marco13 hat gesagt.:


> Das kachelt ja beim ersten Durchlauf ohenhin ab


dummerweise nicht  ... das Objekt wurde ja gültig erstellt (und es sind ohnehin nur Daten [vgl. Strukt]) ... solange wie das Objekt(bzw. die Daten) auf dem Heap nicht zerstört werden, ist der Rückgabewert funktionsfähig ... der ist es auch so noch, selbst wenn ein neues Objekt an die Speicherstelle überschrieben wird ... das ist C++

ich hatte eher Probleme beim Umstieg von C auf Java (bzw. C#) - das nicht mehr Aufräumen müssen ist/war irritierend


----------



## KuhTee (27. Jul 2011)

mogel hat gesagt.:


> dummerweise nicht  ... das Objekt wurde ja gültig erstellt (und es sind ohnehin nur Daten [vgl. Strukt]) ... solange wie das Objekt(bzw. die Daten) auf dem Heap nicht zerstört werden, ist der Rückgabewert funktionsfähig ... der ist es auch so noch, selbst wenn ein neues Objekt an die Speicherstelle überschrieben wird ... das ist C++


Nur hast du kein objekt auf dem heap erstellt, sondern auf dem stack. Und wenn du von dem objekt die adresse zurücklieferst, wird schon der compiler sagen, dass das keine gute idee ist.



Marco13 hat gesagt.:


> ```
> vector<Complex> v = somewhere.get();
> ```
> schreibt, wird dort AFAIK standardmäßig jedes mal eine Tiefe Kopie (!?!) erstellt. Das kann teuer werden, wenn man nicht aufpasst.


Das war es, was ich mit meinem ersten beitrag meinte: man muss (bzw sollte) wissen wie das in c++ funktioniert, wenn man es korrekt benutzen möchte.
Sinnvollerweise erstellt man natürlich in deinem beispiel eine referenz:

```
vector<Complex>& v = somewhere.get();
```
Was aber nicht zwingend nötig (oder sinnvoll, hängt ja auch davon ab, was get() liefert) ist. Denn es ist ja nicht zwingend eine "tiefe" kopie. Tiefe kopie würde bedeuten, dass das vector objekt und _alle_ enthaltenen Complex objekte kopiert werden. Nun kann ich den vector aber durchaus auch so implementieren, dass sich die kopie eines vectors die daten mit dem original vector teilt und nur bei bedarf (wenn die daten geändert werden) kopiert wird.

Noch ein wort zu den referenzen: wer die auf dem müll werfen will, dem fehlen definitiv gute c++ kenntnisse. Und natürlich können die das eigentlich problem lösen. Um zu sagen wie, dafür fehlt aber einiges an quellcode (der ist einfach zu sehr zusammengekürzt).


----------



## Marco13 (27. Jul 2011)

Wie oben angedeutet ist meine aktivere C++-Zeit schon ein paar Jahre her, und auch damals waren die Kenntnisse eher "low-level" (von C kommend) und nicht so sehr auf "gutes Design komplexerer Anwendungen" bezogen, deswegen ist alles, was ich dazu sage, unter dem Vorbehalt möglicher Irrtümer zu sehen. 

Aber soweit ich weiß wird bei einer Zuweisung wie
vector<Complex> v = someOtherVector;
mit einem normalen STL-vector ein neuer Vector erstellt, und alle Elemente einzeln mit dem (ach, wie hieß das gleich wieder? Dieses Mittelding aus Copy Construktor und Zuweisung ... "Assignment Operator"?) "kopiert", was bei nicht explizit überschriebenem Operator eine ensprechende Zuweisung/Kopie der einzelnen Fields durchführt. Vielleicht täusche ich mich da aber auch, da lasse ich mich gerne korrigieren.

Und wie auch schon erwähnt sollte man "wenn möglich" Referenzen verwenden - insbesondere, wenn man z.B. einen vector per setter übergibt ([c]void set(vector<int> &v)[/c] statt [c]void set(vector<int> v)[/c], und noch irgendwo ein 'const' reingemischt  ). 

Aber (auch wenn es mir schon fast unbehaglich ist, das zuzugeben) : Meine Sicherheit in bezug auf das Wissen, was dort passiert, findet bei sowas eine jähe Grenze: Wenn man sowas macht wie
[c]vector<Complex>& v = somewhere.get();[/c]
Dann müßte doch eigentlich trotzdem eine Kopie erstellt werden - denn wenn sie keine Kopie erstellt würde, wäre mir nicht klar, was hier passiert:

```
vector<Complex>& v = somewhere->get();
delete somewhere;
// Was ist 'v' jetzt?
```
(Erstaunlich, wie schnell man da auf so grobgranularer Ebene "rauskommt", wenn man sich nicht öfter und intensiver damit beschäftigt  )


EDIT: Beim weiteren Nachdenken... hätte ich sogar Zweifel, ob sowas wie
[c]vector<Complex>& v = somewhere.get();[/c]
überhaupt geht - da schwirrt in meinem Hinterkopf irgendeine Fehlermeldung dazu rum... ach, ich muss wirklich mal wieder ein paar Zeilen C++ machen... :rtfm:


----------



## KuhTee (27. Jul 2011)

Ja, bei einem std::vector wird glaube ich der komplette inhalt kopiert. Es gibt aber ja durchaus auch andere vector implementierungen.
Abgesehen davon: wenn der inhalt aus pointern besteht, werden wiederrum nur die pointer kopiert, nicht die objekte dahinter 



> Wenn man sowas macht wie
> [c]vector<Complex>& v = somewhere.get();[/c]
> Dann müßte doch eigentlich trotzdem eine Kopie erstellt werden - denn wenn sie keine Kopie erstellt würde, wäre mir nicht klar, was hier passiert:
> 
> ...


Es hängt davon ab, was get() liefert. Wenn get so implementiert ist:

```
vector<Complex> SomeWhere::get() {... }
```
Hält man am ende die referenz auf eine kopie, das delete hat dann keine auswirkung.
Wird allerdings tatsächlich eine referenz zurückgeliefert:

```
vector<Complex>& SomeWhere::get() {... }
```
hängt es davon ab, was der vector<Complex> in SomeWhere ist. Es könnte ja einfach nur ein pointer sein, der nicht von SomeWhere gelöscht wird oder auch nur eine referenz die von einer dritten klassen an SomeWhere übergeben wurde. Wie gesagt, man muss da schon aufpassen. Wenn man den java weg gewohnt ist, kann man da ganz schnell stolpern und weiss nichtmal warum.



> EDIT: Beim weiteren Nachdenken... hätte ich sogar Zweifel, ob sowas wie
> [c]vector<Complex>& v = somewhere.get();[/c]
> überhaupt geht - da schwirrt in meinem Hinterkopf irgendeine Fehlermeldung dazu rum... ach, ich muss wirklich mal wieder ein paar Zeilen C++ machen... :rtfm:


Es wird dann nicht funktionieren, wenn get() eine const referenz liefert. Was häufig der fall sein wird. Dann muss mans natürlich so schreiben:
[c]const vector<Complex>& v = somewhere.get();[/c]


----------



## Marco13 (27. Jul 2011)

Ahja, dann lag ich ja gar nicht sooo falsch mit meinen dunklen Erinnerungen.
Dass es meistens "Praktisch" wäre, wenn der Vector nur Pointer enthielte, ist auch klar, aber dann kommt das gleiche Problem ja auf einer weiteren Ebene hinzu. Irgendwann landet man dann eben bei sowas wie

```
#include "someBoostStuff.h"
...
boost::shared_ptr<std::vector<boost::shared_ptr<std::complex> > > vector;
```
Da ist mir ein
[c]List<Complex> list;[/c]
doch lieber


----------



## maki (27. Jul 2011)

Auf die Gefahr hin mich zu blamieren, aber könnte man nicht den Vector getrennt von der WaveFunction erzeugen, also sozusagen Aggregation anstatt Komposition anwenden?


----------



## Marco13 (27. Jul 2011)

Soweit ich das verstanden hatte, IST die WaveFunction gerade der vector mit den Werten. Aber darum geht's hier ja schon lange nicht mehr  (  sorry)


----------



## maki (27. Jul 2011)

Marco13 hat gesagt.:


> Soweit ich das verstanden hatte, IST die WaveFunction gerade der vector mit den Werten. Aber darum geht's hier ja schon lange nicht mehr  (  sorry)


Worauf ich hinaus wollte, war dass man in C++ eher Aggregation nimmt anstatt Komposition, weil dann nicht mehr die WaveFunkction für das erzeugen und zerstören des Vectors verantwortlich ist.

Sagte doch dass ich mich blamieren werde :lol:


----------



## Gast2 (27. Jul 2011)

KuhTee hat gesagt.:


> Nur hast du kein objekt auf dem heap erstellt, sondern auf dem stack.


ai karamba - stimmt feif:



> Und wenn du von dem objekt die adresse zurücklieferst, wird schon der compiler sagen, dass das keine gute idee ist.


wenn die Compiler das inzwischen machen, dann ist das super


----------



## Illuvatar (27. Jul 2011)

Da hab ich ja mal eine Diskussion losgetreten. Mal sehen was ich noch dazu sagen kann:

Zu meinem konkreten Problem: Ich hab jetzt, wie von einigen vorgeschlagen, ein einfaches reference counting eingebaut. Wobei einfach in diesem Kontext bedeutet, dass es anfangs mal einfach war - und im Laufe der Zeit immer mal ergänzt werden musste  Das für mehr als eine Klasse zu machen, wäre natürlich grober Unfug (oder ist es das jetzt schon?) - da wünschte ich mir fast einen Mechanismus wie in Objective-C. Aber jetzt erstmal (natürlich wieder gekürzt), was da jetzt so rauskam:

```
#include <vector>
using std::vector;
#include "cmp.h"

class WaveFunction {
private:
	vector<cmp> const * values;
	WaveFunction(vector<cmp> const *values_) :
		values(values_), references(new int(1)) {
	}

	// reference counting
	int * references;

public:
	WaveFunction(const WaveFunction& other); // copy constructor
	WaveFunction& operator= (WaveFunction const& rhs);

	static WaveFunction create(int N);

	virtual ~WaveFunction();
};

WaveFunction::WaveFunction(const WaveFunction& other) :
	values(other.values), references(other.references) {
	(*references)++;
}

// besonders unschön... aber besser gehts nicht oder?
WaveFunction& WaveFunction::operator=(WaveFunction const& rhs) {
	if (this != &rhs) {
		(*references)--;
		if (*references == 0) {
			delete values;
			delete references;
		}
		values = rhs.values;
		references = rhs.references;
		(*references)++;
	}
	return *this;
}

WaveFunction::~WaveFunction() {
	(*references)--;
	if (*references == 0) {
		delete values;
		delete references;
	}
}

WaveFunction WaveFunction::create(int N) {
	vector<cmp>* values = new vector<cmp> (N);
	// werte berechnen...
	return WaveFunction(values);
}
```
Naja, immerhin funktioniert es  
Zu meiner Vorgehensweise:


			
				muckelzwerg hat gesagt.:
			
		

> Das ist jetzt nicht böse gemeint, aber wenn Du bei so einem Programm Smartpointer usw. wirklich BRAUCHST und sie nicht nur deshalb verwenden willst, weil Du Dich aus Javasicht sonst nicht wohl fühlst, solltest Du vielleicht etwas mehr mit C++ üben.





			
				KuhTee hat gesagt.:
			
		

> Meine erfahrung ist, dass c++ neulinge, die von java kommen, sich grundsätzlich verrennen, wenn es darum geht objekte hin und her zu reichen. Dann wird kopiert, wo man referenzen verwenden sollte, und ratzfatz knallt es oder man wundert sich, warum das übergebene objekt sich anders verhält als erwartet.


Ich will nicht bestreiten dass das wohl wahr ist  Mein Gedankengang war ja wohl auch in etwa so:
"Das ist nur ein winziges Projekt, also werd ich nicht mit externen Libraries etc anfangen. Aber ich will etwas von C++ mitkriegen, also werd ich so tun als wäre es ein größeres Projekt und versuchen, das alles schön hinzukriegen" (wobei schön aus meiner Sicht möglicherweise äquivalent zu "so wie in Java" ist)
was im Nachhinein betrachtet auch mir nicht ganz logisch erscheint  Aber deshalb hat mir jetzt auch das einfache reference counting gereicht, um fertig zu werden.
Was hab ich gelernt?
- Ich sollte nicht vergessen, dass es Referenzen gibt.
- Bei wirklich größeren Projekten, boost etc verwenden
- Aggregation ist in C++ wohl oft besser. In meinem Fall fand ich das "logisch" nicht sinnvoll... aber einfacher hätte ich es gehabt.
Anmerken möchte ich aber noch, dass Referenzen halt aber doch kein Allheilmittel sind. In meinem Beispiel: Der Vector wird in der create-Methode erstellt. Wenn ich keinen Pointer verwende, kann ich machen was ich will - am Ende diese Methode wird der Vector gelöscht, er muss also mindestens einmal kopiert werden. Und mit dem einfachsten Ansatz


Marco13 hat gesagt.:


> ```
> class X {
> vector<Complex> v;
> void set(vector<Complex> arg) { v = arg; }
> ...


mit dem ich auch angefangen habe, werden sogar _zwei_ tiefe Kopien erstellt.



Marco13 hat gesagt.:


> ```
> #include "someBoostStuff.h"
> ...
> boost::shared_ptr<std::vector<boost::shared_ptr<std::complex> > > vector;
> ```


Ich *glaube* vector macht da intern irgendwas furchtbar intelligentes, was irgendwann mehrere Generationen Historiker beschäftigen wird, um es zu verstehen  Deshalb würde ich aber hoffen, dass der innere shared_ptr nicht benötigt wird?


> Da ist mir ein
> [c]List<Complex> list;[/c]
> doch lieber


Da sind wir uns doch einig 



Marco13 hat gesagt.:


> // Welchen Wert hat der Reference Counter hier?


Hm. Ich weiß um ehrlich zu sein nicht sicher, ob meine Implementierung mit Pointern umgehen kann. Aber ich denke, bei mir wäre der Zähler einfach bei 1... und solang das WaveFunction-Objekt an sich nicht kopiert wird, bleibt er das auch. Mein Zähler zählt ja gewissermaßen, wie viele WaveFunction-Objekte sich einen vector teilen - nicht die Referenzen auf ein WaveFunction-Objekt. Das hieße, es könnte funktionieren, aber ich werde es vorsichtshalber nicht mehr ausprobieren


----------

