map am ende löschen?
-
volkard schrieb:
damit ich mir das besser vorstellen kann, bei welcher klasse zuletzt?
Ich habe gerade ein Spielobjekt, in das der Benutzer im Editor ein Bild laden kann. Da er das Objekt erst platzieren muss, bevor er seine Eigenschaften ändern kann, muss es leider einen Leerzustand geben, den du ja nicht unbedingt magst.
Oder die Kartenteile, die acht optionale Randerweiterungen in einem scoped_ptr<Edge>[8] halten. Oder das Spielbasisobjekt, dass seine Eventverwaltung in einem scoped_ptr speichert und erst bei Bedarf erstellt (um die Masse der Objekte, die keine Events haben, klein zu halten). Naja, ist halt ein Spiel. Vielleicht ist das Beispiel ja trotzdem ernst zu nehmen.Ansonsten verwende ich scoped_ptr auch sehr oft, wenn ein Objekt nicht schon in der Initialisierungsliste erstellt werden kann, weil die Argumente erst im Konstruktor zusammengebaut werden müssen. Aber sehr schön finde ich das ehrlich gesagt nicht; das ist aber eher ein Workaround um die nervige Regel, dass man Objekte nicht frei im Konstruktorcode initialisieren kann.
komisch. mache ich mir nie gedanken um exception sicherheit? irgendwie sehe ich zwar das problem, aber es ist nicht normal für mich.
Ich finde es auch sehr konstruiert in dem Beispiel und hab schon befürchtet, dass du das andere Interface bevorzugen würdest. Vielleicht ist das ja tückischer:
Personal::Personal() { // Lade Standardangestellte vector<string> dateinamen = ladeAngestelltenListe(); for (size_t i = 0; i < dateinamen.size(); ++i) ersetzeAngestellten(i, new Angesteller(dateinamen[i])); }
Dann führt eine Exception zu einem Leak, weil ~Personal nicht ausgeführt wird. Damit das schlimm wäre, müsste Angestellter irgendwelche wichtigen Resourcen wie Datenbankhandles halten, oder so... Ich gebe zu: Ein Personalverwalter wird vermutlich einen nothrow-Konstruktor haben. Aber etwas allgemeiner betrachtet: Jedes Objekt, dass sich im Konstruktor mehrere Resourcen holt, die jeweils eine Exception beim Holen werfen können, muss theoretisch try-Blöcke drum setzen, weil der Destruktor die Arbeit nicht machen kann. Und das kommt, wenn auch nicht in Personalverwaltern, zumindest bei mir öfter vor.
Wie auch immer: Man muss sich Gedanken machen, und mit smart-ptrs tue ich das nicht mehr und konzentriere mich auf andere Dinge.
-
operator void schrieb:
Ich habe gerade ein Spielobjekt, in das der Benutzer im Editor ein Bild laden kann. Da er das Objekt erst platzieren muss, bevor er seine Eigenschaften ändern kann, muss es leider einen Leerzustand geben, den du ja nicht unbedingt magst.
stimmt. mag den leerzustand nicht.
Oder die Kartenteile, die acht optionale Randerweiterungen in einem scoped_ptr<Edge>[8] halten.
*notizmach*
Oder das Spielbasisobjekt, dass seine Eventverwaltung in einem scoped_ptr speichert und erst bei Bedarf erstellt (um die Masse der Objekte, die keine Events haben, klein zu halten). Naja, ist halt ein Spiel. Vielleicht ist das Beispiel ja trotzdem ernst zu nehmen.
oh, in meinem Spielbasisobekt steht im dtor ein delete eventVerwaltung;.
Ansonsten verwende ich scoped_ptr auch sehr oft, wenn ein Objekt nicht schon in der Initialisierungsliste erstellt werden kann, weil die Argumente erst im Konstruktor zusammengebaut werden müssen. Aber sehr schön finde ich das ehrlich gesagt nicht; das ist aber eher ein Workaround um die nervige Regel, dass man Objekte nicht frei im Konstruktorcode initialisieren kann.
geht bei mir normalerweise, weil ich kleinere klassen habe.
Aber etwas allgemeiner betrachtet: Jedes Objekt, dass sich im Konstruktor mehrere Resourcen holt, die jeweils eine Exception beim Holen werfen können, muss theoretisch try-Blöcke drum setzen, weil der Destruktor die Arbeit nicht machen kann. Und das kommt, wenn auch nicht in Personalverwaltern, zumindest bei mir öfter vor.
bei mir nicht. wierd an eine-klasse-ein-zweck liegen. allerdings baue ich auch mal ne klassem, die eingeführt wird, um mir das aufräumen abzunehmen.
Personal::Personal() { // Lade Standardangestellte vector<string> dateinamen = ladeAngestelltenListe(); for (size_t i = 0; i < dateinamen.size(); ++i) ersetzeAngestellten(i, new Angesteller(dateinamen[i])); }
in diesem fall hätte ich das pure besitzen der angestellten von restlicher verwaltung wie laden/speichern getrennt. die besitzende liste räumt sicher auf, egal, wie ich an andere stelle damit umgehe.
dann hätte ich mir überlegt, ob ich das nicht recht oft brauchen könnte und nen adapter um vector gebaut, der für zeigerobjekte da ist, die beim vom-vector-gelöscht-werden ihren pointee deleten. eventuell. ich hab ja schon robleme, außer zeigern auch noch referenzen einzusehen. wie soll ich da noch 5 zeigersorten einsehen? aber container mit kleinen zusatzfeatures (policies?) find ich normal und klasse.notiz von oben: scoped_ptr<Edge>[8] ist natürlich jetzt nr, damit ich es leichter lesen kann. in wirklichkeit haste da ne array-klasse, die keine zusatzkosten hat, aber ein ASSERT im op[]. die würde ich noch mit nem parameter versehen, daß die zeiger mit 0 initialisiert werden und beim löschen deleted werden.
-
volkard schrieb:
notiz von oben: scoped_ptr<Edge>[8] ist natürlich jetzt nr, damit ich es leichter lesen kann. in wirklichkeit haste da ne array-klasse, die keine zusatzkosten hat, aber ein ASSERT im op[]. die würde ich noch mit nem parameter versehen, daß die zeiger mit 0 initialisiert werden und beim löschen deleted werden.
Wenn man boost::array ein assert() verpasst, ist boost::array<scoped_ptr<Edge>, 8> doch genau was du willst. Es ist beim Deklarieren mehr Tipparbeit, dafür hat es 0 Overhead und man muss keine eigene Klasse dafür schreiben. Und man muss weder beim Löschen, noch beim Neuzuweisen (in diesem Fall läuft das wirklich über edgeArray[3].reset(new Edge(...))) ein delete aufrufen... Warum soviel Arbeit machen?
-
in diesem fall hätte ich das pure besitzen der angestellten von restlicher verwaltung wie laden/speichern getrennt.
Klingt bei allgemeinen Personalmanagern gut. Andererseits: Wenn der Personalmanager in der Anwendung wirklich nur dafür da ist, dass eine konkrete, persistente Liste von Angestellten verwaltet wird, hättest du damit nicht einen der allgemein vermeidenswerten Leerzustände, wenn du im Konstruktor nicht direkt lädst? Ich finds ja auch immer toll, wenn der Konstruktor schon die komplette Arbeit für mich macht.
Aber zugegebener Maßen, ich glaube, das ganze Personal-Beispiel hilft mir in diesem Thread nicht viel.volkard schrieb:
Aber etwas allgemeiner betrachtet: Jedes Objekt, dass sich im Konstruktor mehrere Resourcen holt, die jeweils eine Exception beim Holen werfen können, muss theoretisch try-Blöcke drum setzen, weil der Destruktor die Arbeit nicht machen kann. Und das kommt, wenn auch nicht in Personalverwaltern, zumindest bei mir öfter vor.
bei mir nicht. wierd an eine-klasse-ein-zweck liegen. allerdings baue ich auch mal ne klassem, die eingeführt wird, um mir das aufräumen abzunehmen.
Naja. Bei sehr neutralen Klassen ist Eine-Klasse-Ein-Zweck gut durchführbar. Aber ein Spielobjekt, das im Konstruktor seine Grafiken und seine Sounds anfordert, hat schon zwei Resourcen, um mal wieder auf mein konkretes Beispiel zurückzukommen (weil ich mich da auskenne
).
-
operator void schrieb:
Klingt bei allgemeinen Personalmanagern gut. Andererseits: Wenn der Personalmanager in der Anwendung wirklich nur dafür da ist, dass eine konkrete, persistente Liste von Angestellten verwaltet wird, hättest du damit nicht einen der allgemein vermeidenswerten Leerzustände, wenn du im Konstruktor nicht direkt lädst? Ich finds ja auch immer toll, wenn der Konstruktor schon die komplette Arbeit für mich macht.
?
natürlich lade ich auch im konstruktor. die nur-besitzende-liste ist member von mir.
oder um genauer zu sein, du machst ja deine entscheidungen davon abhängig, wieviel man tippen muss, ich erbe von der nur-besitzenden-liste.
-
operator void schrieb:
Naja. Bei sehr neutralen Klassen ist Eine-Klasse-Ein-Zweck gut durchführbar. Aber ein Spielobjekt, das im Konstruktor seine Grafiken und seine Sounds anfordert, hat schon zwei Resourcen, um mal wieder auf mein konkretes Beispiel zurückzukommen (weil ich mich da auskenne
).
ich mich zwar nicht, aber ich sehe das problem nicht bei
class Spiel{ Grafik grafik; Sound sound; };
schwierig scheint es erst zu werden, wenn du mit zeugern umeinand wirfst, wo gar keine hingehören.
oft schreibe ichmain(){ Grafik grafik; Sound sound; Spiel spiel(&grafik,&sound); ... }
man müßte mal gründlich diskutieren, ob das spiel die grafik-engine und soundengine besizuen soll und erzeugen soll, oder ob es die engines nur benutzen soll. der thread muss über meh als 100 beiträge gehen, wenn wir's richtig machen wollen.
-
es muß andere gründe dafür geben, vector<scoped_ptr<Foo*>> zu benutzen. evtl besseres verhalten bei resize(), unique(), erase() oder solchen sachen? wenn ja, bei welchen und müßte man, wollte man nen vector anbieten, der beim wegwerfen von elementen noch ne zusätzliche destroy-sache aufruft, viel code anfassen oder könnte man im neen vector bleiben?
-
vector<scoped_ptr<Foo*>>
Das geht doch gar nicht!
Auf jeden Fall nicht wenn du boost::scoped_ptr meinst. Der ist nicht kopierbar.
-
no copy schrieb:
vector<scoped_ptr<Foo*>>
Das geht doch gar nicht!
Auf jeden Fall nicht wenn du boost::scoped_ptr meinst. Der ist nicht kopierbar.richtig.
die sprache war bloß von
boost::array<boost::scoped_ptr<Edge>, 8>
jo, da hab ich keine fragen, wie ein notboost::array<Edge,8,DeleteOnKill> funktionieren würde.
-
volkard schrieb:
man müßte mal gründlich diskutieren, ob das spiel die grafik-engine und soundengine besizuen soll und erzeugen soll, oder ob es die engines nur benutzen soll. der thread muss über meh als 100 beiträge gehen, wenn wir's richtig machen wollen.
Stimmt, aber zumindest will ich noch klären, dass ich mit Spielobjekt ein Objekt eines Spiels (also nen Stein oder Spieler oder...) meinte, nicht ein Objekt, das ein Spiel repräsentiert
-
wie war das? in nen vector kann ich scoped_ptr nicht stecken? in
ein boost::array aber schon? jetzt mach ich mir aber gedanken, was
los ist, wenn ich später mich mal enscheiden mag, daß ein array
nicht fixed sized ist, sondern halt ein wenig auch mal seine größe
ändern kann. dan mußte ich von scoped_ptr nach shard_ptr umsteigen.würde es klassen geben, wie ich sie mir vorstellen, dann könnte man
einfach zwichen fixed-sized und var-sized anhand eines templateparameters
umschalten und das wär's. ob daher meine verrückte annahme kommt, der
container würde gut besitzer sein können und sich ums löschen kümmern
müssen können?
hattest mich schon so weit gehabt, daß ich mir vornahm, beim nächsten
mal verschärft scoped_ptr einzusetzen und zu schauen, wie es sich
bei seegang anfühlt. aber jetzt hab ich dazu gar keine lust mehr. ich
muss ja viel zu viel aufpassen, wenn ich scoped_ptr benutze statt roher
zeiger. nee, wenn der container verantworlich ist, ist es mir lieber.