Geht das eleganter?
-
Oh, sorry, dann hatte ich das falsch verstanden. Ich dachte, es würden gemischt floats, ints usw drinstehen.
Vielleicht kann man sich der Lösung von einer anderen Seite nähern: Was machst du denn alles mit den Daten? Was für Funktionen wendest du darauf an, wie und wo modifizierst du die Daten oder liest welche aus?
-
Badestrand schrieb:
Was machst du denn alles mit den Daten?
Nur lesen, sonst nichts.
-
SucherDerEleganz schrieb:
Badestrand schrieb:
Was machst du denn alles mit den Daten?
Nur lesen, sonst nichts.
Komm schon, nicht so wortkarg, welchen Weg nehmen die Daten? Wohin werden sie weiterverarbeitet? Oder spannst du sie einfach nur ständig für Rechenoperationen ein, wie du im Anfangspost gezeigt hast:
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; }? Weil dann kannst du sie auch alle in einem double-Container speichern, da passen sowohl Bytes, als auch floats und ints super rein.
-
Ich greife eben ausschließlich lesend auf die Daten zu (und multiplizere den Wert dann, aber das is ja egal), so wie in dem kurzen Code-Ausschnitt. Eigentlich brauche ich also nur sowas:
data[index] * bla;
aber das geht ja leider nicht, da data vom Typ void* ist.Und ich denke das Speichern von BYTEs oder ints in einem double Array wäre nicht so ratsam

-
Nexus schrieb:
@ drakon:
Wieso verwendest du statt deines Beispiels nicht einfach Container? Oder ging es nur darum, die Einsatzmöglichkeit von Templates zu erläutern?Nein. Er will ja je nach Datenyp, der in der Datei steht eine andere Klasse haben, was genau der Anwendungszweck von Templates ist.
Die Klasse hat einen void* foo und der Ctor bekommt ein Flag übergeben, dass der Klasse sagt aus was die Datei besteht. Also im Pseudocode:
Allerdings kommt die Vermutung auf, dass er das zur Laufzeit entscheiden möchte. Was dann die naheliegende Lösung über virtuelle Funktionen suggeriert.
-
google mal nach dem factory pattern, vielleicht gibt dir das einen Anreiz was du machen könntest. So spärlich wie du mit deinen Informationen umgehst kann dir leider auch nur spärlich geholfen werden.
Ganz grob skizziert würde ich es so machen:- 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.
-
SucherDerEleganz schrieb:
Und ich denke das Speichern von BYTEs oder ints in einem double Array wäre nicht so ratsam

Warum denn nicht, oder gibt's Speicherplatzprobleme? Wie viele Werte sind's denn ungefähr?
-
pumuckl schrieb:
So spärlich wie du mit deinen Informationen umgehst kann dir leider auch nur spärlich geholfen werden.
Hm, ich habe doch bereits alles genau beschrieben?!
Aber ich kann ja gerne nochmal alles wiederholen:
Das ist die Klasse:public: void* data; Foo(DATA_TYPE dataType) { if(m_dataType == TYPE_BYTE) data = new BYTE[X]; else if(m_dataType == TYPE_FLOAT) data = new FLOAT[X]; // Hier lese ich jetzt eine raw Datei und fülle damit das Array data };In Methoden von Foo greife ich dann lesend auf die Daten zu:
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; }wobei ich eben jedesmal leider eine Fallunterscheidung machen muss.
Wie ich das mit tr1::array machen könnte ist mir nicht wirklich klar (da muss ich ja einen Typ angeben aber den kenne ich erst zur Laufzeit). Und wie das mit dem Factory Pattern gehen soll is mir auch nicht klar - wie würde denn da der Ctor von Foo aussehen?pumuckl schrieb:
Warum denn nicht, oder gibt's Speicherplatzprobleme?
Das hätte doch nur Nachteile. Wenn ich ein double array anlege und das mit chars fülle, dann bedeutet data[1] ein offset von sizeof(double) und ich erreiche z.B. danmit gleich den 8 char. Die chars davor sind nicht erreichbar. Außerdem muss ich trotzdem wieder rumcasten, damit das Bitmuster richtig interpretiert wird.
-
SucherDerEleganz schrieb:
Badestrand schrieb:
Warum denn nicht, oder gibt's Speicherplatzprobleme?
Das hätte doch nur Nachteile. Wenn ich ein double array anlege und das mit chars fülle, dann bedeutet data[1] ein offset von sizeof(double) und ich erreiche z.B. danmit gleich den 8 char. Die chars davor sind nicht erreichbar. Außerdem muss ich trotzdem wieder rumcasten, damit das Bitmuster richtig interpretiert wird.
edit: Also einfach so (mit Textdatei values.txt):
#include <iostream> #include <fstream> #include <algorithm> #include <vector> int main() { // Datei öffnen std::ifstream file( "values.txt" ); if ( ! file ) return 0; // Datei einlesen std::vector<double> arr; std::copy( std::istream_iterator<double>(file), std::istream_iterator<double>(), std::back_inserter(arr) ); // Werte ausgeben for ( size_t i=0; i<arr.size(); ++i ) std::cout << arr[i] << std::endl; // Oder auch: std::copy( arr.begin(), arr.end(), std::ostream_iterator<double>(std::cout,"\n") ); }
-
SucherDerEleganz schrieb:
Hm, ich habe doch bereits alles genau beschrieben?
Mitnichten. Und der Nick passt auch nicht zu den geposteten. Den "Eleganz" suchst du nicht, dann würdest du dein gesamtes Design nochmal überdenken und nicht so verbohrt auf deinen unsauberen Codeschnipsel sein. Alles was ich von dir gelesen habe ist eher die Suche nach Effizienz was aber meistens der Eleganz zu wieder läuft.
cu André
-
@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.