Standardcontainer für rohen Speicher
-
Also technisch gesehen, ist dein Beispiel völlig i.O. Du legst einen sequenziellen Speicherbereich an (das garantiert vector), und füllst ihn in deiner Funktion. Und dann gibst du den Speicherbereich zurück, als Value-Objekt.
Im optimalen Fall macht der Compiler keine Kopie, schau mal nach RVO (Return Value Optimazation).
Wenn du sicher gehen willst, das keine Kopie entsteht, machst du das so, das du den Aufrufer einen Vector übergeben lässt:
void foo(std::vector<char> &data) { // data füllen }Oder du kannst auch einen Pointer bzw. besser Smartpointer zurück geben:
std::tr1::shared_ptr<std::vector<char>> foo() { std::vector<char> data(1234567); // data füllen return std::tr1::shared_ptr<std::vector<char>> data_p(v); }Dann braucht sich der Aufrufer gar keine Gedanken machen.
-
std::tr1::shared_ptr<std::vector<char>> foo() { std::vector<char> data(1234567); // data füllen return std::tr1::shared_ptr<std::vector<char>> data_p(v); }Du hast jeweils in Z. 1 und 5 die angle brackets falsch gesetzt (das sind Eingabe-streams).
-
Hacker schrieb:
std::tr1::shared_ptr<std::vector<char>> foo() { std::vector<char> data(1234567); // data füllen return std::tr1::shared_ptr<std::vector<char>> data_p(v); }Du hast jeweils in Z. 1 und 5 die angle brackets falsch gesetzt (das sind Eingabe-streams).
Mein Compiler schluckt die problemlos

Übrigens sind das keine Eingabe-Streams, es ist einfach der >> Operator.
-
Sorry, du hast recht, das ist ein Operator.
Und übrigens, mein Compiler schluckt es nicht.
Besser ist also, gleich die sicherere Variante zu nehmen, auch wenn es bei manchen Compilern wegoptimiert wird.Error:
D:\Eigene Dateien\C++ PROGRAMMS\Temp.cxx|8|error: '>>' should be '> >' within a nested template argument list|
-
Ist in C++11 so erlaubt: http://www2.research.att.com/~bs/C++0xFAQ.html#brackets
D.h., dein Compiler unterstützt dieses Feature einfach nur noch nicht (oder es muss explizit aktiviert werden)

-
Ich habe mir so etwas ähnliches wie eine Iterator-Abstraktion für Rastergrafiken gebaut. Eine Bildladeroutine sieht dann in etwa so aus:
template<class Sink> auto bildformatxyz_load(char const* filename, Sink sink) -> decltype(sink(0,0)) { // header lesen... const long width = ...; const long height = ...; auto const navigator = sink(width,height); auto const stepx = navigator.make_offset(1,0); for (long y=0; y<height; ++y) { // Zeile irgendwie einlesen -> puffer auto locator = navigator.make_locator(0,y); for (long x=0; x<width; ++x) { *locator = puffer[x]; locator += stepx; } } return navigator; }Konzept "Navigator" (ähnlich wie ein Iterator-Paar):
- hat Referenzsemantik
- weiß, wie groß ein Raster ist
- weiß, wie man es navigiert
- kann "Lokators" und "Offsets" erzeugen.Konzept "Locator" (ähnlich wie ein Iterator):
- zeigt auf ein Element eines Rasters
- Zugriff per Dereferenzierung
- unterstützt + und - im Zusammenhang mit OffsetsKonzept "Offset" (ähnlich wie difference_type):
- relative Raster-KoordinateEinfaches Beispiel für ein lineares Speicherlayout
template<class T> class linear_navigator { public: typedef typename std::remove_const<T>::type value_type; typedef T* locator_type; typedef std::diff_t offset_type; linear_navigator(); linear_navigator(T* base, long width, long height std::diff_t stepx, std::diff_t stepy); offset_type make_offset(long x, long y) const { return stepx_*x + stepy_*y; } locator_type make_locator(long x, long y) const { return base_ + make_offset(x,y); } long width() const {return width_;} long height() const {return height_;} private: T* base_; long width_, height_; std::diff_t stepx_, stepy_; };Und der Aufruf könnte so aussehen:
std::vector<int> graylevels; auto navi = bildformatxyz_load(filename,[&](long w, long h)->linear_navigator<int>{ const long numelems = w*h; graylevels.resize(numelems); return {&graylevels.front(),w,h,1,w}; }); cout << navi.width() << endl; cout << navi.height() << endl;wobei man den vektor für ein Raster selbst kapseln kann und dann so etwas schreiben kann:
raster<int> graylevels; bildformatxyz_load(filename,into(graylevels)); cout << graylevels.width() << endl; cout << graylevels.height() << endl;Vielleicht findet das ja noch jemand anders praktisch so.
-
c++0x schrieb:
D.h., dein Compiler unterstützt dieses Feature einfach nur noch nicht (oder es muss explizit aktiviert werden)

Kennst du (oder irgendwer sonst) ein Flag o. so, mit dem dass beim GNU GCC ginge... ?
-
Container schrieb:
pumuckl schrieb:
Container schrieb:
Danach kommen die Farbwerte, die muss ich einfach irgendwie in den Speicher stopfen, das war's.
Nö, die wirst du nicht einfach nur in den Speicher stopfen wollen, sondern später sicherlich noch weiterverarbeiten. Sonst bräuchtest du sie garnicht erst einlesen.
Wie werden sie also weiterverarbeitet? Davon hängt ab, wie sie abgelegt werden sollten.Die werden in den Video-Ram geschrieben und dann wieder gelöscht. Und im Video-Ram wird da auch nicht viel mehr mit gemacht, als einfach an bestimmten Stellen auf den Bildschirm kopiert.
Falls du das mehrmals pro Sekunde machst, solltest du nicht immer neuen Speicher anfordern, sondern den gleichen verwenden.
-
Hacker schrieb:
c++0x schrieb:
D.h., dein Compiler unterstützt dieses Feature einfach nur noch nicht (oder es muss explizit aktiviert werden)

Kennst du (oder irgendwer sonst) ein Flag o. so, mit dem dass beim GNU GCC ginge... ?
Versuch mal -std=c++0x
-
--std=c++0x
-
Ja, geht - Danke!

-
Container schrieb:
Hallo!
Welchen Standardcontainer nutzt ihr, wenn es einfach um "rohen" Speicher geht, der in einem Schritt angefordert wird? vector?
Ja, vector<char> bzw. manchmal vector<unsigned char>.
Und verlasst ihr euch auf solche Optimierungen oder übergebt ihr den vector als Referenz?
Wenn die Funktion in performance-kritischen Abschnitten zum Einsatz kommt, dann übergebe ich Referenzen.
Die Kopie für's return kann zwar meist wegoptimiert werden, aber was immer bleibt ist dass der vector in der Funktion 1x neu angelegt wird.Wenn man dagegen eine Referenz auf einen bestehenden vector übergibt, dann kann der aufrufende Programmteil diesen "recyclen". Das kann einiges sparen.
-
@krümelkacker
Gibt es wirklich Fälle wo "stepx_" != 1 wird?
-
hustbaer schrieb:
@krümelkacker
Gibt es wirklich Fälle wo "stepx_" != 1 wird?Sicher. Anderes Speicherlayout (mit stepy_==1), Rotation um 90°, Unterabtastung, ...
raster<int> r = ...; auto nav2 = rotate90(r.all()); auto nav3 = subsampleby2(r.all());
-
OK, wenn man diese Operationen/Fälle auch unterstützen will/muss, dann wird stepx_ natürlich != 1.