array versus boost::array
-
Hallo,
warum sollte man in C++ boost::array den C-array vorziehen?
wegen den Iteratoren, wegen dem Range-check bei Verwendung von at(),
wegen der Größeninformationen bei Übergabe an eine Template-Function.
Man kann sie prinzipiell an eine template-function übergeben, die für
std::vector geschrieben ist, da sie die gleichen typedefs hat.Gibt es weitere Gründe?
Kann ich eigentlich ein irgendwie ein boost::array übergeben und die
Größeninformationen in einer nicht-Template-Function abfragen?Gruß,
Newbie
-
Newbie19 schrieb:
Hallo,
warum sollte man in C++ boost::array den C-array vorziehen?
Garnicht. Wenn du C++ kannst, wirste keine Probleme mit C-Arrays haben.
Boost is eher was für Theoretiker und Frickler.
-
ralf22 schrieb:
Newbie19 schrieb:
Hallo,
warum sollte man in C++ boost::array den C-array vorziehen?
Garnicht. Wenn du C++ kannst, wirste keine Probleme mit C-Arrays haben.
Boost is eher was für Theoretiker und Frickler.
Sollte diese Aussage einfach nur provokativ sein oder meinst du das ernst?
Ansonsten schreib mal beispielsweise eine Template-Funktion, die dir die
Summe aller Elemente eines int[] und eines std::vector<int> berechnet.
Du musst es doppelt implementieren. Bei Verwendung von boost::arrays nicht, oder?
-
Newbie19 schrieb:
Sollte diese Aussage einfach nur provokativ sein oder meinst du das ernst?
Ziemlich sicher nur ein Troll
Newbie19 schrieb:
Ansonsten schreib mal beispielsweise eine Template-Funktion, die dir die Summe aller Elemente eines int[] und eines std::vector<int> berechnet. Du musst es doppelt implementieren. Bei Verwendung von boost::arrays nicht, oder?
Nein, das stimmt so nicht:
#include <numeric> #include <iostream> int main() { int arr[] = { 1, 2, 3, 4, 5, 6 }; std::vector<int> vec(arr, arr + 6); int total = std::accumulate(arr, arr + 6, 0); std::cout << "Total arr: " << total << std::endl; total = std::accumulate(vec.begin(), vec.end(), 0); std::cout << "Total vec: " << total << std::endl; return 0; }
Zu deinen bisher aufgelisteten Vorteilen, gibt es noch zwei wichtige Vorteile von
boost::array
/std::tr1::array
gegenüber C Arrays. Sie sind nicht so stark flüchtig. Aus einem C Array wird innert kürzester Zeit ein Zeiger ohne Informationen mehr über das ursprüngliche Array. Auch bietenboost::array
/std::tr1::array
die Möglichkeit der Kopie an, was man bei einem normalen C Array nicht einfach so machen kann.Und das Beste am ganzen ist noch, dass man all diese Funktionalität ohne irgendwelche Nachteile bekommt.
Grüssli
-
Aus der Kopiersemantik resultiert auch vor allem der Vorteil, dass man boost::array problemlos als Parameter oder Rückgabewert verwenden kann. Ich hatte mal einen Algorithmus, der erforderte, dass ein Array rekursiv per Call-by-Value übergeben wird (die Änderungen in der aufgerufenen Funktion sollten sich in der aufrufenden Funktion nicht auswirken). Da man C-Arrays nur per Referenz übergeben kann, wäre das ein Krampf geworden, ich hätte immer ein lokales Array einrichten müssen und die Elemente kopieren. Mit boost::array ging das aber ohne zusätzliche Anpassungen problemlos.
-
Newbie19 schrieb:
Kann ich eigentlich ein irgendwie ein boost::array übergeben und die
Größeninformationen in einer nicht-Template-Function abfragen?Nicht direkt. Warum brauchst du das? Ist für die Fälle, wo die Grösse dynamisch abgefragt werden soll, ein
std::vector
nicht geeigneter?
-
Nexus schrieb:
Newbie19 schrieb:
Kann ich eigentlich ein irgendwie ein boost::array übergeben und die
Größeninformationen in einer nicht-Template-Function abfragen?Nicht direkt. Warum brauchst du das? Ist für die Fälle, wo die Grösse dynamisch abgefragt werden soll, ein
std::vector
nicht geeigneter?Hi Nexus,
ich dachte da z. B. an den Fall eines OutputStreams, wo ich beliebige Daten
reinschreiben kann, die dann komprimiert werden. Dabei können verschiedene
Komprimierungstypen verwendet werden, die zur Laufzeit gewählt werden.
Also ein virtueller operator<<(const boost::array<char, int>),
wo bei ich allerdings nicht auf Zeichen verzichten möchte, so dass wegen
\0 kein std::string verwendet werden kann.Danke für alle eure Antworten!
Gruß,
Newbie
-
Nein, da musst du wohl Templates nehmen. Um einem möglichen Template-Bloat (durch etliche Instanziierungen erzeugter Laufzeitcode-Overhead) vorzubeugen, könntest du innerhalb eine Nicht-Template-Methode aufrufen, die weniger generisch ist und z.B. einzelne
char
s verarbeitet.
-
Natürlich kann ich mir einen eigenen Typ schreiben, der die Größeninformation
nicht als template-Parameter beinhaltet.
Ich würde nur gerne wissen, ob bereits Klassen existieren, die genau
diesen Fall behandeln.
-
Ah...
gotcha!
Du dachtest an etwas wie:
template<typename T, std::size_t N>
mystream& operator<<(mystream& stream, const boost::array<T, N>& array){
stream.write(array.c_array(), N);
return stream;
}als Brücke, oder?
-
Hier nochmal mit Code-Tags:
template<std::size_t N> mystream& operator<<(mystream& stream, const boost::array<char, N>& array){ stream.write(array.c_array(), N); return stream; }
wobei T, wenn ich es mir richtig überlege kein Template-Parameter ist
-
wobei mystream die Basisklasse aller meiner möglichen streams ist.
-
In deinem Fall ist aber wirklich zu überlegen, ob ein
vector
nicht günstiger wäre.Also:
mystream& operator<<(mystream& stream, const std::vector<char>& v){ stream.write(&v[0], v.size()); return stream; }
Das hätte zum einen den Vorteil, dass nicht für jede Größe eine neue Funktion instantiiert wird, zum anderen könntest du da eventuell flexibler beim Erstellen der Daten sein (ich kenne deine Algorithmen nicht, aber offenbar willst du dynamische Daten in ein statisches
array
stecken. Das stelle ich mir ziemlich kompliziert vor). Außerdem hat dervector
auch wenig Overhead, v.a. wenn du mitreserve
schon vorher genug Speicher reservierst.
-
ipsec schrieb:
Das hätte zum einen den Vorteil, dass nicht für jede Größe eine neue Funktion instantiiert wird
Wieso das? Dabei handelt es sich doch dann um einen Funktionsaufruf, der
geinlined(?) wird. Das ist quasi als ob ich eine virtuelle Funktion mit
2 Parametern und Rückgabewert direkt aufrufe, oder?
Deine std::vector Befürwortung kann ich verstehen. Die Funktion mit dem
boost::array schließt ja eine Funktion für einen Vektor nicht aus
Im Fall des std::vector<char> kann man den operator<< aber doch auch als member-Funktion machen
Aber es kommt auch schonmal vor, dass man ein paar fixe Bytes reinschreiben möchte.
Die Verwendung von reserve ist mir auch bekannt.Danke euch!!!
-
ipsec schrieb:
Das hätte zum einen den Vorteil, dass nicht für jede Größe eine neue Funktion instantiiert wird,
Das ist kein so großer Vorteil. Wie Newbie schon schreibt wird der op<< bei jedem einigermaßen vernünftig optimierenden Compiler eh geinlined und die Template-Instantiierug selber kostet nur minimal Compilezeit.
Du könntest die Template-Instantiierung auch verstecken:
mystream& operator<< (mystream& stream, boost::iterator_range<char*> ir) { stream.write(ir.begin(), ir.end()); return stream; } /* ... */ boost::array<char, 15> ba15; boost::array<char,3> ba3; std::vector<char> vec; mystream& ms; ms << ba15; // iterator_range hat einen impliziten (template-)Konstruktor für Container, // und zwar Container.begin() bis Container.end() ms << ba3; // - und array<char,N>::iterator ist char* ms << boost::make_iterator_range(&vec.front(), &vec.back()); //naja...
Die verstecke Template-Instantiierung findet hier beim impliziten Aufruf des Konvertierungs-Konstruktors von array<> nach iterator_range<> statt. Da iterator_range aber nur ein Paar aus iteratoren (in dem Fall Zeigern) ist, kann der Compiler da mit ziemlicher Sicherheit fast alles wegoptimieren und übergibt am Ende tatsächlich nur die beiden Pointer aus dem Array an stream.write()