2010-11-23 4 views
2

Ich habe eine zweidimensionale Matrix von Zellen. Normalerweise arbeiten nur unsichtbare Algorithmen mit diesen Zellen. Aber manchmal möchte ich jede Zelle sichtbar zu machen, damit ich einen Zeiger auf ein grafisches Objekt hinzugefügtTun optionale Elemente brechen RAII und wenn ja, was ist ein besserer Ansatz?

class Cell 
{ 
    ... 
    QAbstractGraphicsItem* representation_; 
    ... 
} 

Der Konstruktor von Zellsätze representation_ auf 0 Manchmal andere Visualisierung Klasse Iterierten auf der Matrix und fügt Elemente zu Zellen, die den Inhalt visualisieren jeder Zelle nach Farben.

Ich denke, das bricht das RAII-Paradigma. Hast du einen besseren Ansatz?

Ich könnte eine andere 2-dimensionale Matrix erstellen und von dort Link auf die ursprüngliche Matrix, so dass die Zeiger auf der Visualisierungsseite sind, aber ich würde dann zwei Matrizen benötigen.

+0

Welchen Teil von RAII betrachten Sie hier als defekt? –

+0

Das representation_ member ist die meiste Zeit 0 und wird nicht initialisiert. – problemofficer

+1

Ich denke, das bricht das MVC-Paradigma mehr als das RAII-Paradigma. – filipe

Antwort

5

RAII ist falsch benannt, wie (ich glaube) Scott Meyers weist darauf hin.

Es sollte nicht „Ressourcenerfassung ist Initialisierung“ genannt werden, es sollte „Destruction ist Ressourcen Release“ bezeichnet werden. Aber wir sind, wo wir sind.

Wenn die Zelle „besitzt“ das Objekt von representation_ spitz, und löscht sie in seinem destructor, dann ist dies immer noch eine Form der RAH ist, die gleiche Art und Weise, dass Sie ein shared_ptr mit einem Null-Zeiger initialisieren können, dann später eingestellt es zu etwas anderem. Ich gehe davon aus, dass Sie es korrekt verwenden (stellen Sie sicher, dass das Objekt unmittelbar nach seiner Erstellung in einer Zelle oder einer anderen Zelle gespeichert wird, ohne dass zwischen dem Abschluss des Konstruktors und dem Speichern des Zeigers irgendwo ein Fehler auftritt, der schließlich freigegeben wird). Wenn ja, verwenden Sie den wichtigen Teil von RAII, obwohl es kein Konstruktor ist, der die Arbeit erledigt.

Es ist wahrscheinlich eine Verletzung der einzigen Verantwortung Prinzip. Sie haben für die eine Zelle Zelle verantwortlich gemacht, und auch für Speicher-Verwaltung dieses QAbstractGraphicsItem Objekt. Es würde wahrscheinlich Dinge vereinfachen, um representation_ zu einem intelligenten Zeigertyp zu ändern, so dass kein spezieller Code im Destruktor von Cell benötigt wird.

Wenn die Zelle das Objekt, auf das representation_ zeigt, nicht "besitzt", dann verletzt das auch RAII nicht inhärent, es implementiert es einfach nicht. Etwas anderes muss für das Eigentum des Objekts verantwortlich sein. Vielleicht benutzt das andere RAII, vielleicht verletzt es es. Um sicherzustellen, dass das Objekt so lange lebt, wie es die Zelle braucht, müsste es irgendwie in den Lebenszyklus der Zelle involviert sein (wenn es zum Beispiel die Zelle besitzt, wäre es vielleicht in Ordnung). Wenn das nicht der Fall ist, besteht eine gute Chance, dass RAII irgendwie verletzt wird.

2

Ich denke, Sie suchen nach der Visitor design pattern.

+0

Das Besuchermuster eignet sich gut für Situationen, in denen Sie eine begrenzte Anzahl von Objekten und eine unbegrenzte Anzahl von Möglichkeiten zum Zeichnen/Darstellen von Objekten haben. Der klassische Besucher fügt zwar die Erweiterbarkeit in eine Richtung hinzu, entfernt sie aber von der anderen. – CashCow

+0

Nachdem ich den Artikel auf Wikipedia gelesen habe, denke ich, dass es zu kompliziert für mein Problem ist. – problemofficer

+0

Yeh, es gibt keine Silberkugel ... –

1

Klingt, als ob Sie Erweiterungseigenschaften wünschen, vielleicht mit Farbinformationen, die nicht von Cell oder den Matrixalgorithmen benötigt werden. Es ist eine sehr dynamisch-sprachliche Herangehensweise.

Der übliche Ansatz für statische Sprachen wie C++ wäre die Unterklasse Cell. Ihre Algorithmen sollten gut auf einer Matrix von CellSubclass funktionieren, obwohl es die Dinge ein wenig komplizierter macht, wenn Sie Elemente sequentiell nach Wert in einem Array speichern. Sie können das fortsetzen und Ihre Algorithmen templatisieren, oder Sie können Zeiger im Array speichern.

Wenn Sie wirklich Erweiterungseigenschaften wollen, aber können Sie ein map<void*,IPropertyValue*> innerhalb Cell verwenden, wo IPropertyValue einfach einen virtuellen Destruktor bietet, so dass Sie nicht die Erweiterung Eigenschaftswerte lecken, wenn eine Cell zu befreien. Sie müssen beim Abrufen des Werts eine Umwandlung durchführen. Verwenden Sie die Adresse einiger privater statischer Variablen als Schlüssel, um Eindeutigkeit und Einheitlichkeit zu gewährleisten.

EDIT: Wenn Sie nur einen Zeiger speichern wollen/müssen, dann wird die Art, wie Sie haben, gut funktionieren. Verwenden Sie jedoch einen intelligenten Zeiger, und verwenden Sie swap bei der Zuweisung. So wird alles RAII sein.

+0

Dies scheint übermäßig kompliziert. Gibt es eine detailliertere Beschreibung? – problemofficer

+0

Der zweite Absatz ist interessant. Ist das nicht ein guter Anwendungsfall für die Mehrfachvererbung? Ich meine eine abstrakte Klasse "IVisualisierbar" und "Klasse VisualizableCell: öffentliche Zelle, öffentliche IVIsualisierbar". Dann wirken Ihre Algorithmen auf 'Cell's, und Ihr Visualizer wirkt auf' IVisualisierbar'. Wenn Sie jetzt keine Zellen mit Zeigern speichern, müssen Sie mit Vorlagenalgorithmen arbeiten, da die Größe eines Zellenobjekts jetzt unbekannt ist. –

2

Ich glaube nicht, du brichst RAII (Resource Acquisition Is Initialization) überhaupt, solange Ihr Handy destructor die QAbstractGraphicsItem Objekt tatsächlich löscht (Destruktor ist virtuell, nicht wahr?), Wenn man dort ist. Sie scheinen jedoch besorgt zu sein über die mögliche Kopplung zwischen Ihren Grafikelementen und Zellen in dieser Architektur.

Ja, es ist attraktiv, den Objektspeicher vollständig von seiner Präsentation zu trennen. Das perfekte Werkzeug dafür (wie von Ben Voigt aufgezeigt) ist etwas, mit dem Sie Ihre Klassendefinition von außerhalb der Klasse um ein zusätzliches Datenelement erweitern können. Aber C++ unterstützt das nicht. Ihr Vorschlag, eine andere Matrix für die Visualisierungszeiger zu behalten, ist die beste, die ich mir vorstellen kann, aber dann müssen Sie diese zweite Datenstruktur pflegen. Wenn Sie das nicht tun wollen, müssen Sie diese perfekte Trennung für praktische Einfachheit opfern.

Angenommen, Sie haben nur eine Visualisierung zu jeder Zeit aktiv, sehe ich kein Problem mit einem einzigen Zeiger in Ihren Zellen für die Verwendung durch das Visualisierungssystem. Ihr Code ist in Ordnung, wie er ist. Ja, Sie binden den Datenspeicher und die Präsentation zusammen, aber es ist ein ziemlich lockerer Link.Ihre Zellen hängen immer noch nicht von irgendetwas ab, das sich auf die Darstellung bezieht, außer dass sie erkennen, dass die Ebene existiert und dass sie möglicherweise einige (undurchsichtige) zellspezifische Daten speichern möchten.

andere Vorschläge zu adressieren, ist das Besuchermuster nützlich für die Visualizer entwerfen, aber das ist ein orthogonaler Auslegungspunkt. Was ist, wenn diese Besucher zusätzliche Daten pro Zelle speichern müssen? Das ist die wahre Frage. Was das Simulieren einer Eigenschaftserweiterung mit einer Map betrifft, ist es kompliziert und es ist auch nicht notwendig, es sei denn, Sie haben mehrere Visualisierungen, die gleichzeitig auf einer einzigen Matrix laufen.

+0

Danke für die Antwort. Ich möchte auch deine akzeptieren, kann aber nur eine auswählen. – problemofficer

0

Es bricht RAII- Sie eine selbstlösende Zeiger verwenden soll.

+0

Meinst du intelligente Zeiger? – problemofficer

+0

@problemofficer: Ja. – Puppy

Verwandte Themen