Suche Implentierungsideen
-
Warum nicht std::vector<char> ? Wirkt für mich natürlicher als std::string.
Simon
-
@volkard: Ah, jetzt hab ichs kapiert

Das geht dann ja auch in die Richtung was die Serialisierungs Sektion bei Parashift erklärt - nur halt eben mit nem String.
Gefällt mir...werd mal bischen rumspielen und schauen, was sich am besten für mich eignet - String, vector oder streamDanke

-
theta schrieb:
Warum nicht std::vector<char> ?
Weil es zum Teil wahnsinnig mühsam ist, in einen
std::vector<char>zu schreiben. Probier mal das aus, was volkard im Beispielcode gezeigt hat:char const* first = reinterpret_cast<char const*>(&magicNumber); char const* last = first + sizeof(magicNumber); outputVector.insert(outputVector.end(), first, last);-> Gah!
Grüssli

-
theta schrieb:
Warum nicht std::vector<char> ?
weil ich's am häufigsten mit string gesehen habe, fiel mir das spontan ein. aber im moment glaube ich, daß ostringstream naheliegender als string ist. wie gut, daß ich das problem nicht habe und Hydrael es rausfinden muß. hehe.
-
volkard schrieb:
theta schrieb:
Warum nicht std::vector<char> ?
weil ich's am häufigsten mit string gesehen habe, fiel mir das spontan ein. aber im moment glaube ich, daß ostringstream naheliegender als string ist. wie gut, daß ich das problem nicht habe und Hydrael es rausfinden muß. hehe.
Werde heute Nacht irgendwann bescheidgeben wie es geklappt hat - aber ausm Bauch heraus denke ich, dass es mit nem ostringstream ziemlich gut klappen müsste

-
ja, da hat Dravere recht.
aber ein wenig später schreibt man sich eh wrappers.template<typename T> writeAny(outputVector<char>& v,T& magicNumber){ char const* first = reinterpret_cast<char const*>(&magicNumber); char const* last = first + sizeof(magicNumber); outputVector.insert(outputVector.end(), first, last); }und später
writeAny(outputVector,magicNumber);dann ists wieder egal.
-
@volkard,
Auch wieder wahr.@Hydrael,
Bin gespannt auf deine Testergebnisse mit demstringstream. Ich persönlich hatte mal einen Fall, wo ichstd::stringObjekte zusammen setzen musste. Seither weiss ich, dass das einfache zusammenfügen vonstd::stringObjekte oft schneller ist, wenn man keinstringstreamverwendet, sondern direkt über diestd::stringMöglichkeiten geht.Grüssli
-
Warum gebt ihr nicht gleich den reinterpret_cast<char const*>(&magicNumber) an den Socket?
-
Themen-Überblick (Aktual schrieb:
Warum gebt ihr nicht gleich den reinterpret_cast<char const*>(&magicNumber) an den Socket?
Weil es ja im Grunde nicht nur um die magicNumber geht, sondern um komplette datenstrukturen. Kann also durchaus auch sowas sein:
struct foo { char bar; int foo1; short bar1; }Und da kann man ganz schnell in memory alignment Geschichten reinlaufen.
-
Die hast du bei memcpy und volkards Methode auch, da macht ihr ja auch nur nen reinterpret cast.
-
So, ich habe jetzt mal ein wenig herumprobiert - letzendlich bin ich beim std::strstream hängengeblieben, weil ich beim stringstream das Problem hatte, dass er die Daten als strings reinterpretiert und ich somit bei den Binärdaten bullshit herausbekommen habe.
Mit dem strstream funktioniert die Sache tadellos und ist auch schön einfach implementierbar

Einen herzlichen Dank an alle Helfer - die Lösung gefällt mir jetzt echt gut.
Einzig zur Performance kann ich momentan noch nichts genaues sagen, da ich die im derzeitigen Projektstand noch nicht realistisch messen kann.Wen es interessiert...meine Klassen sehen jetzt folgendermaßen aus (diesmal am Beispiel eines anderen Pakets, so dass zu sehen ist, wie ich mit strings umgehe):
Basisklasse
#pragma once /// SYSTEM INCLUDES #include <strstream> /// PROJECT INCLUDES /// LOCAL INCLUDES /// FORWARD DECLARATIONS namespace netCodeCommon { class CUDPPacket { //////////////////////// PUBLIC ////////////////////////// public: /// Constructor CUDPPacket( ) { } /// Destructor virtual ~CUDPPacket() { } ///////////// METHODS ///////////// OPERATORS ///////////// ACCESSORS virtual const size_t DataLen() const = 0; virtual const size_t TotalLen() const = 0; const int ID() const { return mID; } virtual const std::strstream& Serialize() = 0; virtual void Deserialize(const std::strstream& data) = 0; ///////////// MEMBERS /////////////////////// PROTECTED /////////////////////// protected: ///////////// METHODS ///////////// OPERATORS ///////////// ACCESSORS ///////////// MEMBERS int mID; std::strstream mSerializationStream; /////////////////////// PRIVATE ////////////////////////// private: ///////////// METHODS ///////////// OPERATORS ///////////// ACCESSORS ///////////// MEMBERS }; } // netCodeCommonAbgeleitete Klasse
#pragma once /// SYSTEM INCLUDES #include <string> /// PROJECT INCLUDES #include <netCode/common/UDPPacket.tpp> #include <netCode/common/exception.hpp> /// LOCAL INCLUDES #include "UDPPacketIDs.h" /// FORWARD DECLARATIONS namespace netCodeCommon { struct S_RegisterPlayerData { S_RegisterPlayerData() : magicNumber(0), playerName("") { } S_RegisterPlayerData(unsigned int magic, const std::string& name) : magicNumber(magic), playerName(name) { } unsigned int magicNumber; std::string playerName; const size_t size() const { return sizeof(magicNumber) + playerName.length(); } }; class CUDPRegisterPlayer : public CUDPPacket { //////////////////////// PUBLIC ////////////////////////// public: /// Constructor CUDPRegisterPlayer(char* data, size_t len) { mID = Type_RegisterPlayer; mSerializationStream.write(data, len); Deserialize(mSerializationStream); } CUDPRegisterPlayer(unsigned int magicNumber, const std::string& playerName) { mID = Type_RegisterPlayer; mData.playerName = playerName; mData.magicNumber = magicNumber; } /// Destructor virtual ~CUDPRegisterPlayer() { } ///////////// METHODS ///////////// OPERATORS ///////////// ACCESSORS virtual const S_RegisterPlayerData& Data() const { return mData; } virtual const size_t DataLen() const { return mData.size() + sizeof(mID); } virtual const size_t TotalLen() const { return mData.size() + sizeof(mID) + sizeof(size_t); } virtual const std::strstream& Serialize() { size_t length = mData.playerName.length(); mSerializationStream.clear(); mSerializationStream.write(reinterpret_cast<char*>(&mID), sizeof(mID)); mSerializationStream.write(reinterpret_cast<char*>(&mData.magicNumber), sizeof(mData.magicNumber)); mSerializationStream.write(reinterpret_cast<char*>(&length), sizeof(length)); mSerializationStream.write(mData.playerName.c_str(), mData.playerName.length()); mSerializationStream.seekg(0, std::ios::beg); return mSerializationStream; } virtual void Deserialize(const std::strstream& data) { size_t length = 0; mSerializationStream.read(reinterpret_cast<char*>(&mID), sizeof(mID)); mSerializationStream.read(reinterpret_cast<char*>(&mData.magicNumber), sizeof(mData.magicNumber)); mSerializationStream.read(reinterpret_cast<char*>(&length), sizeof(length)); char *tmp = new char[length + 1]; mSerializationStream.read(tmp, length); tmp[length] = '\0'; mData.playerName = tmp; mSerializationStream.clear(); } ///////////// MEMBERS /////////////////////// PROTECTED /////////////////////// protected: ///////////// METHODS ///////////// OPERATORS ///////////// ACCESSORS ///////////// MEMBERS /////////////////////// PRIVATE ////////////////////////// private: ///////////// METHODS ///////////// OPERATORS ///////////// ACCESSORS ///////////// MEMBERS S_RegisterPlayerData mData; }; } // netCodeCommon
-
Hydrael schrieb:
letzendlich bin ich beim std::strstream hängengeblieben, ...
std::strstreamist deprecated und es ist wahrscheinlich, dass in zukünftigen Versionen des Standards diese Klasse nicht mehr existieren wird.Hydrael schrieb:
weil ich beim stringstream das Problem hatte, dass er die Daten als strings reinterpretiert und ich somit bei den Binärdaten bullshit herausbekommen habe.
Wie hast du denn in den
std::stringstreamgeschrieben? Aber nicht mit demoperator <<? Es gibt nämlich einewriteMethode, welche du nutzen solltest:
http://www.cplusplus.com/reference/iostream/ostream/write/Den
std::stringstreamzudem mit dem Flagstd::ios::binaryerstellen, damit die Daten beim Schreiben nicht verändert werden.Grüssli
-
sieht gut aus.
aber warum nicht
virtual void Serialize(std::strstream& data) = 0; virtual void Deserialize(std::strstream& data) = 0;damits gleicher aussieht. der returnwert war eh fake. und const auf einem stream gleube ich dir nicht.
uups, nee, dann schon gleich
virtual void Serialize(std::ostrstream& data) = 0; virtual void Deserialize(std::istrstream& data) = 0;uups, dann gleich
virtual void Serialize(std::ostream& data) = 0; virtual void Deserialize(std::istream& data) = 0;dann kannst du mit derselben funktion auch in dateien speichern und daraus laden.
oder gar im netz nach einer sockestream-implementierungen suchen, falls es sowas gibt.
-
Dravere schrieb:
std::ios::binaryDas war es, was mir gefehlt hatte

@volkard: Der const stream war noch ein copy/paste überbleibsel - ist mir kurz nach dem posten auch aufgefallen.
Ansonsten hab ich deine Anmerkungen auch noch übernommen.
Wie man sieht bin ich nicht so sehr fit mit streams. Hatte die bisher immer nur für file I/O benötigt und da war mir oldschool fread/fwrite irgendwie immer lieber
Schönen Dank euch beiden