array versus boost::array
-
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()