Geht das eleganter?
-
@Badestrand: Dein Code klappt nicht. arr[i] liefert nun mal immer doubles...
Ich habe das Problem EXAKT beschrieben. Und natürlich sollte es "elegant" UND effizient sein (was kein Widerspruch ist). Naja, da mir offenbar niemand ein paar konkrete (!) Codeschnippsel zeigen kann, bleibe ich einfach bei meinem void*.
-
SucherDerEleganz schrieb:
Naja, da mir offenbar niemand ein paar konkrete (!) Codeschnippsel zeigen kann, bleibe ich einfach bei meinem void*.
Dein Problem - hier stört es niemanden, wenn du unsauberen Code schreibst.
Dir wurden viele Vorschläge genannt. Wenn du nicht selbst in der Lage bist, diese umzusetzen, können wir dir auch nicht helfen. Gerade pumuckl hat doch einige Ansätze erläutert.
-
SucherDerEleganz schrieb:
@Badestrand: Dein Code klappt nicht. arr[i] liefert nun mal immer doubles...
Der Code klappt und natürlich liefert er immer doubles

Guck dir mal dein Codestückchen an:
if(m_dataType == TYPE_FLOAT) { y = (static_cast<FLOAT*>(foo))[index] * scaleY; } else if(m_dataType == TYPE_BYTE) { y = (static_cast<BYTE*>(foo))[index] * scaleY; }Da spielt es absolut keine Rolle, ob du Bytes einliest, das Byte mit scaleY multiplizierst und y zuweist, oder das Byte als double hast und dieselbe Rechnung durchführst. Und weil du dasselbe Ergebnis rausbekommst, nehmen sich die Lösungen nichts, außer dass die void*-Lösung durch den new-Overhead und Fragmentierung mehr Speicher verbraucht.
-
[quote="Nexus"]Dein Problem - hier stört es niemanden, wenn du unsauberen Code schreibst.
1. Ist er nicht unsauber. Er ist die einfachste Lösung und wohl auch die effizienteste. Ich wollte nur wissen, ob es auch eine mehr C++igere Möglichkeit gibt.Nexus schrieb:
Dir wurden viele Vorschläge genannt. Wenn du nicht selbst in der Lage bist, diese umzusetzen, können wir dir auch nicht helfen. Gerade pumuckl hat doch einige Ansätze erläutert.
Vorschläge? Wo denn bitte? Alles was immer kam ist "du beschreibst dein Problem zu ungenau". Gehts noch? Das Problem ist todessimpel und hinreichend erklärt. Und der Tipp von pumuckl ist auch nicht sehr hilfreich, denn im Grunde sagt er nur "Factory Pattern". Kein konkretes Codeschnipsel, nichts. Der einzige konkrete Tipp ist es, dass ich (egal welche Datentyp es ist) die Daten immer in ein double array packe. Das wäre nicht nur schlecht sondern auch falsch.

Ansonsten danke für nichts.
-
SucherDerEleganz schrieb:
die Daten immer in ein double array packe. Das wäre nicht nur schlecht sondern auch falsch.
Das verstehe ich nicht - dann sag doch mal konkret, warum du es schlecht und falsch findest.
Stimmst du mir denn zu, dass du bei
BYTE ausgelesener_wert = ...; y = ausgelesener_wert * sonstwas;und
BYTE ausgelesener_wert = ...; double als_double = static_cast<double>( ausgelesener_wert ); y = als_double * sonstwas;das Selbe herausbekommst?
-
SucherDerEleganz schrieb:
Nexus schrieb:
Dein Problem - hier stört es niemanden, wenn du unsauberen Code schreibst.
1. Ist er nicht unsauber. Er ist die einfachste Lösung und wohl auch die effizienteste....
Was hat den "sauber" (also geringe Fehleranfälligkeit bei Nutzung, Weiterentwicklung und wartung)
mit "einfach" (was sich wohl eher an den Fähigkeiten des Programmierers orientiert)
oder "effizient" (was eher mit Algorithmen, Volumina und Rechnerkapazitäten zu tun hat)
zu tun ?"void*-Code" (im Allgemeinen und Deiner auch) ist einfach fehleranfällig und sobald es sauberere Lösungen gibt (so wie hier), ist der Code einfach "unsauber".
Mag sein, dass Du ihn als "einfach" empfindest (anscheinend auch als "einfacher" als die saubereren Lösungen - vermutlich, weil Du sie und ihre Vorteile nicht durchschaust).
Und dass er effizient ist, kann/will ich auch nicht beurteilen (dazu fehlen einfach Angaben) - aber "sauber" ist er einfach nicht.Gruß,
Simon2.
-
@Badestrand: Wenn ich ein double array chars einlese, wie komme ich denn dann bitte an den 3. char ran?
Simon2 schrieb:
mit "einfach" (was sich wohl eher an den Fähigkeiten des Programmierers orientiert)
Simon2 schrieb:
oder "effizient" (was eher mit Algorithmen, Volumina und Rechnerkapazitäten zu tun hat)
zu tun ?Es ist effizient, weil es ohne Schnörkel ist. Keine Funktionsaufrufe, keine Polymorphie usw. Einfach ein roher Speicherbereich.
Simon2 schrieb:
"void*-Code" (im Allgemeinen und Deiner auch) ist einfach fehleranfällig und sobald es sauberere Lösungen gibt (so wie hier)
Wo ist denn eine der hier geposteten Lösungen? Abgesehen von dem Brocken "Factory Pattern" sehe ich hier nichts. Wo ist beispielhafter Code etc.?
Simon2 schrieb:
Mag sein, dass Du ihn als "einfach" empfindest (anscheinend auch als "einfacher" als die saubereren Lösungen - vermutlich, weil Du sie und ihre Vorteile nicht durchschaust).
Auf die erneute Provokation (sagt ja einiges über deinen Charakter aus) geh ich mal wieder nicht ein. Man kann keine Vorteile von Lösungen sehen, wenn keine genannten wurden. Eine Lösung ist sowas wie: Du könntest ein tr1::array nehmen und dann folgendes machen: <Code>
Sowas gab es hier nie. Nur das blöde "zu ungenaue Beschreibung", da kann man nicht konkret helfen. lol..Simon2 schrieb:
Und dass er effizient ist, kann/will ich auch nicht beurteilen (dazu fehlen einfach Angaben) - aber "sauber" ist er einfach nicht.
An der Effizienz eines rohen Arrays gibt es nichts zu diskutieren. Dass es in C++ (!) eleganter ginge mag sein, drum bin ich ja hier. Aber da keine KONKRETEN Vorschläge kamen (CODE!), lass ich es einfach beim void*.
(PS: Auch interessant, anstatt konkrete Vorschläge zu machen kommt nur Meta Gelaber und plumpe Provokationen von dir Simon2
)
-
SucherDerEleganz schrieb:
@Badestrand: Wenn ich ein double array chars einlese, wie komme ich denn dann bitte an den 3. char ran?
Mit dem dritten Element vom Array, also
arr[2]. Und das funktioniert eben, weil in dem double-Array nur doubles drin sind, welche rein kommen, indem du die Bytes aus der Datei in doubles umwandelst.
Hast du eigentlich eine Text- oder Binärdatei?
-
pumuckl schrieb:
- Untersuche, welche Programmteile abhängig von dem Datentyp sind
- definiere eine Schnittstelle zu diesen Programmteilen, die Schnittstelle muss unabhängig von dem Typ sein
- diese Schnittstelle deklarierst du als abstrakte Klasse
- definiere ein klassentemplate (templateparameter ist der typ), das diese Schnittstelle implementiert
- erstelle eine factory(-methode), die ermittelt welcher typ verwendet wird und die entsprechende Schnittstellenimplementation zurückliefert.damit hast du den typabhängigen teil gekapselt und fertig.
Hier stehts doch. Jeder Schritt erklärt. Wenn du dich nicht in der Lage fühlst das umzusetzen, solltest du eventuell noch ein paar C++ Bücher lesen und noch ein bisschen lernen, oder gleich aufgeben. Die Implementierung eines Factory-Patterns sollte für jeden Programmierer mit > 1 Jahr Erfahrung eine Kleinigkeit sein. Mit den Erläuterungen oben eventuell auch für einen Anfänger.
Ach ja, Badestrand schrieb bereits, dass die void* Lösung ineffizient ist, da Bytes und Floats bei jedem Zugriff in doubles gecastet werden. Bei vielen Zugriffen wirkt sich das recht negativ aus (vor allem die Umwandlung Byte->Double). Also die Daten direkt als double einzulesen ist wesentlich effizienter als sie bei jedem Zugriff wieder umzuwandeln. Deine Lösung ist also nicht nur unsauber (in C++ verwendet man void* sehr selten), sondern auch ineffizient gegenüber der naheliegendsten Lösung, die Daten direkt als double einzulesen.
Warum du diesen Weg nicht gehen willst hast du bisher noch nicht erklärt. Deshalb kann man dir keinen brauchbaren Hinweis bezüglich einer eleganteren Lösung geben.
Gruß
Don06
-
edit: Nö, ist mir doch zu doof, sowas von undankbar.
-
SucherDerEleganz schrieb:
Deine plumpen Provokationen kannst du dir übrigens sparen.
Du solltest nicht gleich alles als Provokation auffassen. Es ist in der Tat so, dass das Verständnis von "einfach" subjektiv ist und davon abhängt, wie schwierig der Programmierer es empfindet, etwas umzusetzen.
SucherDerEleganz schrieb:
Ja, ich habe noch nicht viel mit Templates gemacht, aber mit C++ kenne ich mich doch einigermaßen aus.
Templates sind aber gerade ein sehr mächtiges Instrument von C++. Und nur weil du sie nicht kennst, musst du sie nicht als schlechte Lösung darstellen.
SucherDerEleganz schrieb:
Es ist effizient, weil es ohne Schnörkel ist. Keine Funktionsaufrufe, keine Polymorphie usw. Einfach ein roher Speicherbereich.
Es ist nicht unbedingt schneller, nur weil es C ist. Eine höhere Abstraktionsebene impliziert keine Verlangsamung des Codes. Von "effizient" würde ich an der Stelle sowieso nicht sprechen, da C++-Mittel meistens effizienter sind (mit weniger Aufwand erreicht man mehr). Abgesehen davon erreicht man durch den eventuellen Geschwindigkeitsvorteil unsicheren und fehleranfälligen Code, was die Bilanz fragwürdig macht...
SucherDerEleganz schrieb:
Wo ist beispielhafter Code etc.?
[...]
Eine Lösung ist sowas wie: Du könntest ein tr1::array nehmen und dann folgendes machen: <Code>
Sowas gab es hier nie. Nur das blöde "zu ungenaue Beschreibung", da kann man nicht konkret helfen. lol..
[...]
Aber da keine KONKRETEN Vorschläge kamen (CODE!), lass ich es einfach beim void*.
[...]
(PS: Auch interessant, anstatt konkrete Vorschläge zu machen kommt nur Meta Gelaber und plumpe Provokationen von dir Simon2
)Ich denke, das hast du nun genug häufig erwähnt. Sag mir bitte, wieso du einfach nicht in der Lage bist, wenigstens zu versuchen, die genannten Möglichkeiten selbstständig umzusetzen. Wenn du sie nicht kennst, kannst du ja recherchieren, z.B. auf www.cplusplus.com. Wenn du dann konkrete Fragen hast, kannst du immer noch fragen. Aber einfach stur darauf zu beharren, dass dir Code-Beispiele gebracht werden, bringt dich nicht wirklich weiter. Eine gewisse Selbstständigkeit sollte man als Programmierer schon besitzen.
-
SucherDerEleganz schrieb:
...Das man den Code eben beim 1. Blick durchschaut. ...
Und das Kriterium soll NICHT vom Wissenstand des Betrachter abhängen ?

Ich kann Deinen Code (oder den der Anderen hier) ja mal meinen 10jährigen Töchtern vorlegen....
Genau DAS habe ich behauptet (dass es von Wissenstand des Betrachters abhängt) - das hatte nichts mit einer Provokation zu tun.
Ich habe nicht einmal behauptet, dass Dein Code NICHT einfach sei - nur, dass "einfach" und "effizient" nicht viel mit "sauber" zu tun haben.SucherDerEleganz schrieb:
...Es ist effizient, weil es ohne Schnörkel ist. Keine Funktionsaufrufe, keine Polymorphie usw. Einfach ein roher Speicherbereich....
Da hast Du aber eine sehr eigene Definition von "effizient". Ich kenne nur die Definition "mit denkbar wenig Einsatz (üblicherweise Speicher und Rechenleistung aber seit einigen Jahren oft auch Entwicklungszeit) zum Ziel". Und das hängt sehr stark von der Aufgabe und dem Rechnerumfeld ab. Das allozieren eines Speicherbereichs zur Laufzeit kann durchaus ineffizienter sein als andere Techniken (z.B. die Stackspeicher verwenden). Auch Polymorphie ist in vielen Fällen nicht ineffizient (und schon gar nicht ineffizienter als wenn man sie selbst mittels if/else nachzubilden versucht).
SucherDerEleganz schrieb:
...sagt ja einiges über deinen Charakter aus...
Aha - Psychologieausbildung abgeschlossen ? (DAS war jetzt eine Provokation :p ;))
Über Charakter und Motivationen sollte man nach meiner Erfahrung bei solchen flüchtigen Internetkontakten besser nicht spekulieren. Ich lasse das auch.SucherDerEleganz schrieb:
...Man kann keine Vorteile von Lösungen sehen, wenn keine genannten wurden. ...
Hmmm - 3. Post (insgesamt die 2. Antwort) enthält bereits einen Vorschlag. 3 Posts weiter wirst Du auf tr::array und std::vector verwiesen, die sich nahezu identisch zu Arrays verwenden lassen - und üblicherweise sogar Arrays einsetzen, so dass sogar der Effizienzaspekt abgedeckt ist. Irgendwie sind hier bei dem von Dir an den Tag gelegten Selbstbewusstsein Alle davon ausgegangen, dass Du mit den Standarddokus und -Beispielen klarkommst.
Du hast übrigens selbst auch nicht gerade besonders viel Code beigesteuert. So ist mir z.B. anhand Deines Codes nicht klar, warum Du überhaupt zwischen diesen verschiedenen Typen unterscheiden musst - und wie "unterschiedlich" Du die verschiedenen Datentypen überhaupt behandeln musst.SucherDerEleganz schrieb:
...Dass es in C++ (!) eleganter ginge mag sein, drum bin ich ja hier. ...
Merkt man aber nicht. So richtig strahlst Du "Annahmebereitschaft" nicht gerade aus.
Aber nun gut. Den templates-Ansatz mal etwas näher an Deinen Fall angepasst:
template <typename> void methode1(vector<T> const& v) ... y = v[index] * scaleY; // keine Fallunterscheidung mehr möglich ... } template <typename T> void fachlichkeit(size_t) { vector<T> v(size); methode1(v); ... } int main() { ... switch(dataType) { case TYPE_BYTE: fachlichkeit<char>(X); break case TYPE_FLOAT: fachlichkeit<float>(X); break ...Wenn für bestimmten Typen fachlichkeit() oder methode1() anders aussehen müssen, kannst Du Spezialisierung nutzen:
template <> void methode1(vector<mySpecialClass> const& v) and_now_for_something_completely_different(v[3]); }Gruß,
Simon2.
-
Badestrand schrieb:
SucherDerEleganz schrieb:
@Badestrand: Wenn ich ein double array chars einlese, wie komme ich denn dann bitte an den 3. char ran?
Mit dem dritten Element vom Array, also
arr[2]. Und das funktioniert eben, weil in dem double-Array nur doubles drin sind, welche rein kommen, indem du die Bytes aus der Datei in doubles umwandelst.Sorry, aber was du da sagst ist einfach falsch. Wenn ich in einem double array arr[2] mache, dann liefert er mir sizeof(double) bytes ab Speicherstelle arr+sizeof(double) und da sizeof(double) nun mal größer als 1 ist (meistens wohl 8), ist 1 Element 8 Byte breit. Auf die einzelnen chars kann ich NICHT zugreifen! Außerdem liefert mir arr[2] einen double, sprich das Bitmuster der chars, oder shorts oder was auch immer wird völlig anders interpretiert. Ansonsten möcht ich dazu nicht mehr eingehen, der Vorschlag ist einfach nur lächerlich;)
@Simon2: Was soll f.[index] bedeuten? Vermutlich meinst du v[index], oder?
Naja, den Code finde ich nicht wirklich so gut. Erstens habe ich ja doch wieder eine Fallunterscheidung drinnen (switch), die ich ja umgehen wollte. Außerdem ist das bei mir so auch nicht verwendbar. Ich brauche ja einen Container/Array als Member, das mir die Daten aus der Datei hält (also ein Pendant zu void* foo). Wie soll das bei deinem Code gehen? Bei Templates muss der Typ ja zur Compilezeit feststehen, es ginge also nur ein tr1::array<int> oder was auch immer, aber das funktioniert nicht. Und ein array<T> könnte ich nur machen, wenn die Klasse eine Template-Klasse ist, was auch wiederrum schlecht ist.Und um 2 (!) Zeilen Code, die mir nicht so gefallen (die 2 Downcasts beim Zugriff aufs void* array), zu verbessern möchte ich nicht wirklich ein Factory Pattern oder sowas programmieren;)
Hätte ja sein können, dass es da irgend nen Trick gibt mit ner Struktur oder typeof oder sonst was. Aber wenn es da keine wirklich simple Alternative gibt (wenig Code), dann lass ich einfach so wie es jetzt ist.
-
@SucheDerEleganz: Der Vorschlag ist nicht lächerlich, du verstehst nur nicht genau, was ich meine
Also ich schlage dir nicht vor, die Bytes einfach roh in den double-Speicher reinzukopieren, denn das wäre total dämlich wie du ja selbst sagst.
Ich schlage stattdessen vor, jeden Zahlenwert in einem double-Wert zu speichern, egal ob es vorher ein char, int oder float war.
Um es wirklich deutlich zu machen (sonst geht das noch 10 mal hin und her): Bei einer Byte-Datei liest du das erste Byte der Datei ein, wandelst dieses Byte in ein double um (der dann logischerweise einen Wert zwischen 0..255 enthält) und pusht diesen double in das Array rein. So hast du dann kein Array aus Bytes/Shorts/.., sondern ein Array aus doubles, wobeibyte_array[i]==double_array[i]gilt, du also bei dem double-Arrayzugriff die selben Werte erhältst, als wenn du die Werte in einem Byte-Array speichern würdest.Hier eine Beispiel-Lade-Funktion:
template<typename T> std::vector<double> loadFile( const char* path ) { // Datei öffnen std::ifstream file( path, std::ios::binary ); if ( ! file ) throw "file could not be loaded"; // Dateigröße ermitteln file.seekg( 0, std::ios::end ); const std::streamsize file_size = file.tellg(); file.seekg( 0, std::ios::beg ); // Die Dateigröße muss mit der Datentypgröße zusammenpassen if ( file_size % sizeof(T) != 0 ) throw "file is corrupt"; // Datei einlesen std::vector<T> raw( file_size / sizeof(T) ); file.read( reinterpret_cast<char*>(&raw[0]), file_size ); // Alle Werte zu doubles konvertieren und zurückgeben return std::vector<double>( raw.begin(), raw.end() ); } int main() { try { std::vector<double> arr = loadFile<char>( "bla.bin" ); // Oder auch: if ( /*ist byte-Datei*/ ) arr = loadFile<char>( "bla.bin" ); else if ( /*ist short-Datei*/ ) arr = loadFile<short>( "bla.bin" ); else if ( ... // Ausgabe der Werte std::copy( arr.begin(), arr.end(), std::ostream_iterator<double>(std::cout,"\n") ); } catch ( const char* err ) { std::cout << "Error: " << err << "!" << std::endl; } }
-
Hehe, ok. Die Aussage "Speicher die Werte einfach alle in einem double Array" war etwas missverständlich;)
Der von dir gepostete Code würde natürlich gehen, aber mal ehrlich.. elegant ist das nicht. Zunächst mal der eklige reinterpret_cast, dann lädst du alles in einen vector des passenden Typs ein, um die Werte dann wieder in einen double vector zu kopieren. Und die enorme Speicherverschwendung wäre auch ein KO Kriterium für mich (ferner sind Operationen wie mul auf doubles langsamer im Vergleich zu ints oder chars, aber das wäre jetzt nicht ausschlaggebend;)Was ich bräuchte wäre sowas wie dynamische Templates:
Foo Member: array<T> foo;
Foo Ctor: Foo(type t) { foo.setType(t); foo.add(...); }
Aufruf: Foo* f = new Foo(int);Aber sowas geht leider nicht^^
-
SucherDerEleganz schrieb:
Aber sowas geht leider nicht^^
Schau dir vielleicht mal Boost.Any und Boost.Variant an. Aber in deinem Fall gibts eigentlich bessere Möglichkeiten, die hier schon erwähnt wurden...
-
SucherDerEleganz schrieb:
Und die enorme Speicherverschwendung wäre auch ein KO Kriterium für mich (ferner sind Operationen wie mul auf doubles langsamer im Vergleich zu ints oder chars, aber das wäre jetzt nicht ausschlaggebend;)
Genau deswegen braucht man mehr Infos von dir. Sag doch gleich, dass du viele Werte oder wenig Speicher hast und deine Rechenzeit knapp ist. Dann hätte ich mir die ganze Mühe nicht machen brauchen. Gr!

-
Außerdem solltest du natürlich auch erwähnen wie viele Werte du grob verarbeiten musst. Viele überschätzen soetwas. Man sollte zunächst sauberen Code schreiben, bevor man zu solchen Hacks wie void* Zeigern greift. Ist die Stelle im Code wirklich so performancerelevant wie du denkst, hat dein Profiler dir das gesagt? Wenn nicht, nimm Badestrands Variante, dass ist für jeden C++ Programmierer wesentlich verständlicher, als dieses void*-Zeug.
-
Badestrand schrieb:
Genau deswegen braucht man mehr Infos von dir. Sag doch gleich, dass du viele Werte oder wenig Speicher hast und deine Rechenzeit knapp ist.
Völlig unerheblich wieviele es sind. Die bis zu 8 (!) fache Speichermenge zu verbraten ist nicht sinnvoll - egal ob ich nun 1000 Daten oder 10^9 habe.
@Don06: Nein, eher nicht. Ich werde keine 50 Zeilen Code schreiben um Zeilen code zu ändern. Abgesehen davon hat mir noch immer keiner geantwortet, wie ich nun bei Badestrands Template Lösung die Daten in der Klasse speichern soll (sprich: was KONKRET jetzt mein void* foo ersetzen soll)
-
SucherDerEleganz schrieb:
Völlig unerheblich wieviele es sind. Die bis zu 8 (!) fache Speichermenge zu verbraten ist nicht sinnvoll - egal ob ich nun 1000 Daten oder 10^9 habe.
Quatsch. Wenn du für Systeme entwickelst, die in der Regel 1-4 GB Arbeitsspeicher haben sind 20 zusätzliche Kilobytes ein Firlefanz und nicht mal erwähnenswert.