Aufgabe2

FloatType{}

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Aufgabe2
Hi…
Schon ca. 8 Studen suche ich den Grund warum das:

           FloatType::FloatType() {
	ff = new float;
}

FloatType::FloatType(float value){	
	ff = new float;
	*ff = value;
}

FloatType::~FloatType() {
	delete ff;
}

size_t FloatType::deserialize(const char *value) {
	char *z = new char[4];
	memcpy(z, value, 4);
	ff = new float; 
	ff = reinterpret_cast<float*>(z);
	delete z;
	return sizeof(*ff);
}

const char * FloatType::serialize() {
	char *z = new char[5];
                            char *blubb = new char;
	blubb= reinterpret_cast<char *>(ff);
	memcpy(z, blubb, 4);
	delete blubb;
	return z;
}
...

nicht funktioniert… :wand: :wand: :wand:

“ff” habe ich im .hpp als float *ff deklariert…

Das Ding ist kompilierbar, aber tut nichts… :cry:
Kann mir jemand helfen?

Danke im voraus.


hei,
na das da:

ff = new float;
ff = reinterpret_cast<float*>(z);

gibt schon mal ein speicherloch. ich nehme an du willst einen float auf ein char bringen und zurück (also nicht textuell), der ansatz ist richtig. versuch mal folgendes (btw: warum machst du den float als zeiger?) :

size_t FloatType::deserialize(const char *value) 
{
    if (ff != NULL)
        delete ff;
    ff = new float;
    std::memcpy(static_cast<char *>(ff), value, 4);
    return sizeof(*ff); // warum gibst du die größe von float zurück? ist immer gleich
}
std::string FloatType::serialize() // wir wollen doch kein speicherleck!
{
    char *tmp = new char[4]; // 4 byte sind genug
    if (ff != NULL)
        delete ff;
    ff = new float;
    std::memcpy(tmp, static_cast<char *>(ff), 4);
    std::string ret(tmp);
    delete [] tmp;
    return ret;
}

wenn du keine strings haben willst empfehle ich ein 4-byte char array in die klasse zu packen, auf das du verweist. andernfalls müllst du deinen speicher zu. ein static_cast sollte hier ausreichen


@Korbinian:

Ich hab’ auch so gedacht, aber Mario Kiefer (studentische Hilfskraft und Autor der Aufgabe) hat in der Newsgroup folgendes geschrieben:

Ich danke dir fuer Hinweis und versuche jetzt etwas zu aendern.


sorry … aber das mit den 5 bytes is kompletter schwachsinn
wenn das float sowieso binär hingerotzt wird dann können da auch schon null bytes in den 4 bytes drin sein … von daher is die terminierung sinnfrei
man kann das was zurückkommt sowieso nicht als c-string interpretieren … das wäre extrem gefährlich …


Wenn ich bis jetzt alles richtig verstanden hab, dann brauchen sie das 0-Zeichen am Ende des Arrays zum prüfen, ob man alles “richtig” macht. Hier ein Stück des Codes, der testet, ob IntType richtig implementiert ist (aus typestester.cpp):

byteArray = it->serialize();

// test if byte array is longer the sizeof int bytes
if ( strlen(byteArray) > sizeof(int) ) {
  cout<< "byteArray longer than needed"<< endl;
  return false;
}

// now test bytearray
read = it2.deserialize(byteArray);

if (read > sizeof(int)) {
  return false;
}

Für einige sehr große Zahlen sind also alle 4 Bytes != 0 und damit muss danach ein 0-Byte kommen, sonst liefert das strlen ein zu großen Wert und man fällt durch den Test. Andererseits muss man in deserialize als Länge 4 byte zurückgeben, sonst fällt man auch durch den Test. Alles ziemlich komisch: serialize verwendet ein 5 byte Array, aber deserialize sagt, dass es nur 4 Byte verwendet hat.
In deserialize teste ich übrigens nicht darauf, ob nach den 4 Byte ein 0-Zeichen kommt. Schließlich werden auch in den Chunks nur 4 Byte gespeichert (ohne das anschließende 0-Zeichen).

Btw: StaticString ist auch so ne ungenau Beschreibung: StaticString speichert Strings mit nicht mehr als LENGTH Zeichen. Wenn es aber weniger sind, dann wird nicht etwa mit Blanks aufgefüllt, sondern einfach nur der Kurze String genommen. Die Angabe, dass StringType eine “statische Größe” hat, ist also falsch. Es sollte wohl besser maximale Größe heißen.


deserialize von Int- und FloatType muss sizeof(int) bzw. sizeof(float) zurückgeben, eben da in den Chunks nur genau so viel Byte für diese Typen extrahiert werden. Die Nullterminierung ist wie schon erwähnt nur für den einen Test nötig, ansonsten würde man sie natürlich weg lassen.

Bei Aufgabe 2b sollte einem der Umgang mit deserialize bald klar werden.

Zu StaticString:
Also ich hab StaticString einfach mit konstant großem char-Array implementiert. Ohne auf StringType zurückzugreifen. In diesem Fall stimmt wohl die Aussage, dass StaticString eine “statische Größe” hat.


also in manchen datenbanken kann man ja angeben wie groß der typ sein soll

e.g.: ein integer mit 3 stellen → 10 bits nötig → 3 bytes eines zur nullterminierung

anderer seits könnte die aufgabenstellen etwas präziser sein, kein unternehmen gibt dir ne so läppische spezifikation


jo, find auch dass das aufwendige an der aufgabe weniger das coden als das verstehen der sehr schwammigen angabe ist…


Ich hab letztes Jahr etwa 2/3 der effektiven Arbeitszeit gebraucht, um überhaupt mal zu verstehn was die von einem wollen, und wie sie ihr System aufgebaut hatten :slight_smile:


noch ne kleine anmerkung :
man kann dieses komische design relativ leicht zu nem halbwegs ordentlichen machen indem man in DataType noch ne interface funk deklariert :
Etwa so :
virtual unsigned long GetCurrentStreamSize (void ) const = 0 ;
die liefert dann zurück wieviele bytes serialize denn schreiben würde bei dem aktuellen objekt … bei int und float also 4 und bei string strlen + 1
Vorteil davon ist dass wenn man das nicht macht man im Tablemanager ständig excessiv dynamic_cast benutzen muss um gerade zu wissen womit man es zu tun hat , mit der funk is das unnötig und man kann ein
DataType * obj immer streamen ohne wissen zu müssen worum es sich handelt …


Die Idee klingt gut ist aber leider nicht möglich.[quote]
Die abstrakte Basisklasse DataType liefert die
entsprechende Schnittstelle. Diese darf nicht verändert werden.
[/quote]


schon mal was vom operator typeid gehört?

voraussetzung ist man hat ne virtuelle funktion oder häufig verwendet man nen virtuellen dekonstruktor

type_info info = typeid(irgendeinpoiner);

if( strcmp(info.name,„Floattype“) == 0)
{
/*du hast nen float */
}

da die typen von ner abstrakten basisklasse abgeleitet wurden kannste es verwenden weil der vtable pointer schon eingebaut ist

haste 2 pointer kannste die type_info s direkt vergleichen

typeid(p1) == typeid(p2)


Nein noch nicht gehört, Danke für den Hinweis.


Vielleicht redet ihr ja vom gleichen und ich blicks nur nicht…
aber in der […]/aufgabe2/src/types/TypeID.hpp steht doch:

namespace umdb {

    //Festlegung der Typenkennung
    enum {STRING_TYPE='1',INT_TYPE='2' ,FLOAT_TYPE='3' };

    //Definition von TypeID
    typedef char TypeID;
}

Kann man nicht einfach das als Grundlage fuer Typerkennung verwenden?

Mfg,
MadDy


In diesem Thread ging es gerade darum, wie ich herausfinde, von welchem Typ ein Zeiger tatsächlich ist. Beispiel:

DataType* p;
p = new IntType();
// Hier möcht ich jetzt wissen, von welchem Typ denn das Objekt ist, auf das p nun zeigt. In diesem Fall: IntType

Dies kann man mit dynamic_cast machen → fällt der fehl, so wars der falsche Typ auf den gecastet werden sollte, oder wie Lord_of_Code eben erklärte mit operator typeid.


der witz an meinem tipp war nicht zu erkennen von was für nem typ ein pointer is … wenn ihr das so macht wie ich meinte könnt ihr euch eben diese if abfragerei ( seis mit dynamic_cast oder typeid ) sparen und könnt von DataType abgeleitete klassen völlig Polymorph de/serialisieren !


Da man die abstrakte Basisklasse nicht verändern darf, ist das so direkt ja leider nicht möglich. Aber man könnte sich von DataType eine weitere Klasse ableiten, z.b. myDataType und erst von dieser Klasse dann die einzelnen Klassen (IntType, FloatType, StringType). Allerdings ist das glaube ich nicht das, was sie sehen wollen.