12 Stimmen

Effiziente Alternativen für die Offenlegung einer Sammlung

Welche Alternativen habe ich in C++, um eine Sammlung unter dem Gesichtspunkt der Leistung und der Datenintegrität darzustellen?

Mein Problem ist, dass ich eine interne Liste von Daten an den Aufrufer zurückgeben möchte, aber ich möchte keine Kopie erzeugen. Somit bleibt mir nur die Möglichkeit, entweder einen Verweis auf die Liste oder einen Zeiger auf die Liste zurückzugeben. Ich bin jedoch nicht verrückt danach, den Aufrufer die Daten ändern zu lassen, ich möchte ihn die Daten nur lesen lassen.

  • Muss ich zwischen Leistung und Datenintegrität wählen?
  • Wenn ja, ist es generell besser, einen Weg einzuschlagen, oder ist dies vom Einzelfall abhängig?
  • Gibt es andere Alternativen?

1voto

Was Sie wollen, ist ein Nur-Lese-Zugriff, ohne den gesamten Datenblock zu kopieren. Sie haben ein paar Möglichkeiten.

Erstens könnten Sie einfach eine const-Referenz auf Ihren Datencontainer zurückgeben, wie oben vorgeschlagen:

const std::vector<T>& getData() { return mData; }

Dies hat den Nachteil der Konkretheit: Sie können nicht ändern, wie Sie die Daten intern speichern, ohne die Schnittstelle Ihrer Klasse zu ändern.

Zweitens können Sie const-ed-Zeiger auf die eigentlichen Daten zurückgeben:

const T* getDataAt(size_t index)
{
   return &mData[index];
}

Dies ist ein bisschen netter, erfordert aber auch, dass Sie einen getNumItems-Aufruf bereitstellen und gegen Out-of-Bounds-Indizes schützen. Auch ist die const-ness Ihrer Zeiger leicht weggeworfen, und Ihre Daten sind jetzt lesen und schreiben.

Eine andere Möglichkeit besteht darin, ein Paar Iteratoren bereitzustellen, was allerdings etwas komplexer ist. Dies hat die gleichen Vorteile von Zeigern, sowie nicht (notwendigerweise) brauchen, um eine getNumItems Aufruf bieten, und es gibt erheblich mehr Arbeit beteiligt, um die Iteratoren von ihrer const-ness zu entfernen.

Am einfachsten lässt sich dies wahrscheinlich durch die Verwendung einer Boost Range bewerkstelligen:

typedef vector<T>::const_iterator range_iterator_type;
boost::iterator_range< range_iterator_type >& getDataRange()
{
    return boost::iterator_range(mData.begin(), mData.end());
}

Dies hat den Vorteil, dass die Bereiche zusammensetzbar, filterbar usw. sind, wie Sie auf der Seite Website .

0voto

Henk Punkte 1704

Die Verwendung von const ist eine vernünftige Wahl. Vielleicht möchten Sie auch die Boost C++-Bibliothek für ihre Shared Pointer-Implementierung überprüfen. Sie bietet die Vorteile von Zeigern, d.h. Sie können die Anforderung haben, einen gemeinsamen Zeiger auf "null" zurückzugeben, was eine Referenz nicht zulassen würde.

http://www.boost.org/doc/libs/1_36_0/libs/smart_ptr/smart_ptr.htm

In Ihrem Fall würden Sie den Typ des gemeinsamen Zeigers konstant machen, um Schreibvorgänge zu verhindern.

0voto

Orion Edwards Punkte 117361

Wenn Sie eine std::list von einfachen alten Daten (was .NET als "Werttypen" bezeichnen würde), dann ist es in Ordnung, eine const-Referenz auf diese Liste zurückzugeben (wobei böse Dinge wie const_cast )

Wenn Sie eine std::list von Zeigern (oder boost::shared_ptr ), dann werden Sie nur daran gehindert, die Sammlung zu ändern, nicht aber die Elemente in die Sammlung. Mein C++ ist zu eingerostet, als dass ich Ihnen die Antwort darauf geben könnte :-(

0voto

Skeve Punkte 252

In den folgenden beiden Artikeln werden einige der Probleme, die mit der Kapselung von Containerklassen verbunden sind, und die Notwendigkeit einer solchen Kapselung näher erläutert. Obwohl sie keine vollständig ausgearbeitete Lösung bieten, führen sie im Wesentlichen zu demselben Ansatz wie der von Shog9.

Teil 1: Verkapselung und Vampire
Teil 2 (zum Lesen ist jetzt eine kostenlose Registrierung erforderlich): Zugwrackbeobachtung
von Kevlin Henney

0 Stimmen

Zu Ihrer Information: Die von Ihnen geposteten Links sind tot.

0 Stimmen

@MM. Danke für den Hinweis, jetzt behoben.

0voto

Agnel Kurian Punkte 55747

Ich schlage vor, Rückrufe zu verwenden, etwa nach dem Muster EnumChildWindows . Sie müssen sich etwas einfallen lassen, um zu verhindern, dass der Benutzer Ihre Daten ändert. Verwenden Sie vielleicht eine const Zeiger/Verweis.

Andererseits könnten Sie eine Kopie jedes Elements an die Callback-Funktion übergeben und die Kopie jedes Mal überschreiben. (Sie wollen nicht eine Kopie Ihrer gesamten Sammlung erstellen. Ich schlage nur vor, eine Kopie von einem Element nach dem anderen zu erstellen. Das sollte nicht viel Zeit/Speicherplatz in Anspruch nehmen).

MyClass tmp;
for(int i = 0; i < n; i++){
    tmp = elements[i];
    callback(tmp);
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X