Kleine String Klasse
-
Du darfst doch in
operator+()dein Objekt nicht ändern...
-
#include <iostream> #include <cstring> using namespace std; namespace dk { class String { private: char* data; int length; // ein vorzeichenloser Typ dürfte sinnvoller sein int data_size; public: String() // die Verwendung der Initialisierungsliste ist zweckmäßig { length = 0; data_size = 0; data = 0; } String(char* data,int length = -1) // Überladung sollte in Erwägung gezogen werden, da die Bedeutung der verscheidenen Aufrufe doch recht stark varriert { // wiederum: Intialisierungsliste verwenden if(length == -1) this->length = strlen(data); else this->length = length; this->data = new char[this->length+1]; strncpy(this->data,data,this->length); // das ist die falsche Funktion, falls der zu kopierende String eingebette '\0' enthält this->data[this->length] = '\0'; this->data_size = this->length+1; } ~String() { delete[] this->data; } String(const String& org) { data = new char[org.data_size]; strcpy(data,org.data); // falsche Funktion, falls '\0' im String length = org.length; data_size = org.data_size; } void operator=(const char* data) // Rügabe überdenken { delete[] this->data; // evtl. auch den Fall a = a.c_str() beachten!; nicht exception-sicher, falls this->length = strlen(data); this->data = new char[length+1]; // hier eine Exception ausgelöst wird, ist der Inhalt von data unbestimmt, der folgende Destruktoraufruf hat folglich UB strncpy(this->data,data,length); this->data[length] = '\0'; this->data_size = length+1; } String& operator+(const String& other) // Rückgabewert überdenken; Funktion sollte const sein { char* old_data = new char[data_size]; strcpy(old_data,data); delete[] data; // wieso nicht gleich old_data = data? length += other.length; data = new char[length+1]; strcpy(data,old_data); // '\0' im String... delete[] old_data; strcat(data,other.data); // '\0' im String data[length] = '\0'; data_size = length+1; return *this; } // op+= in Betracht ziehen und Implementierung über + (oder umgekehrt, ist aber bei Strings wenig sinnvoll) void operator=(const String& other) // Rückgabewert überdenken { delete[] this->data; // Selbstzuweisung beachten !!! this->length = other.length; this->data = new char[length+1]; strncpy(this->data,other.data,length); // '\0' im String this->data[length] = '\0'; this->data_size = length+1; } // an copy&swap denken void assign(const char* data,int length = -1) //the same as operator=() but with length parameter { delete[] this->data; // siehe oben: a.assign(a.c_str()); nicht exception-sicher if(length == -1) { this->length = strlen(data); } else this->length = length; this->data = new char[this->length+1]; strncpy(this->data,data,this->length); // '\0' im String this->data[this->length] = '\0'; this->data_size = this->length+1; } const char* c_str() const { if(data) return this->data; else return ""; } char* g_dat() //if needed, data can be modified { if(data) return this->data; else return "ERROR g_dat()!"; // illegal in C++11; ganz schlechte Idee sowieso, weil der Aufrufer keine Möglichkeit hat, zu erkennen, dass ein Fehler aufgetreten ist // direkte Rückgabe von data oder eine Exception erscheinen zweckmäßiger } int size() // const { return this->data_size; } int len() // const { return this->length; } }; }
-
Vielen Dank für eure Vorschläge (vor allem an camper).
Du darfst doch in operator+() dein Objekt nicht ändern...
Also muss ich eine Kopie erstellen?
strncpy(this->data,data,this->length); // das ist die falsche Funktion, falls der zu kopierende String eingebette '\0' enthält
Ah ok, dann muss ich mir diese Funtkion selbst schreiben.
// illegal in C++11; ganz schlechte Idee sowieso, weil der Aufrufer keine Möglichkeit hat, zu erkennen, dass ein Fehler aufgetreten ist
// direkte Rückgabe von data oder eine Exception erscheinen zweckmäßigerIch habe versucht data direkt zurückzugeben, aber dann tritt ein Fehler auf.
-
string master schrieb:
Ich habe versucht data direkt zurückzugeben, aber dann tritt ein Fehler auf.
Was denn für ein Fehler?
-
String operator+(const String& other) const { String result(c_str(), size()+other.size()); memcpy(result.g_dat()+size(), other.c_str(), other.size()); return result; }setzt allerdings den Konstruktor in seiner gegenwärtig defekten Form voraus

-
Ich hab jetzt das nochmal überarbeitet (außer strcpy mit 0Byte). Habt ihr noch Verbesserungsvorschläge? (Bis Mittwoch muss ich fertig sein).
#include <iostream> #include <cstring> #include <string> #include <sstream> #include <bitset> #include <algorithm> using namespace std; namespace dk { class String { private: char* data; unsigned int length; unsigned int data_size; //length + 1 public: friend ostream& operator<<(ostream &os,const String &str); friend istream& operator>>(istream &is,String &str); String() : length(0),data_size(0) { data = 0; } String(const char* data,int length = -1) //if length == -1 ,strlen() will find out. { //length parameter is used for strings where 0 bytes aren`t only at the end if(length == -1) this->length = strlen(data); else this->length = length; this->data = new char[this->length+1]; strncpy(this->data,data,this->length); this->data[this->length] = '\0'; this->data_size = this->length+1; } String(string data) { this->length = data.size(); this->data = new char[this->length+1]; strncpy(this->data,data.c_str(),this->length); this->data[this->length] = '\0'; this->data_size = this->length+1; } String(const int freq,const char letter) : length(freq) { data = new char[freq+1]; memset(data,letter,freq); data_size = length+1; data[length] = '\0'; } ~String() { delete[] this->data; } String(const String& org) { data = new char[org.data_size]; strcpy(data,org.data); length = org.length; data_size = org.data_size; } const String& operator=(const char* data) { delete[] this->data; this->length = strlen(data); this->data = new char[length+1]; strncpy(this->data,data,length); this->data[length] = '\0'; this->data_size = length+1; return *this; } const String& operator=(const String& other) { delete[] this->data; this->length = other.length; this->data = new char[length+1]; strncpy(this->data,other.data,length); this->data[length] = '\0'; this->data_size = length+1; return *this; } const String operator+(const String& other) { String ret("",length+other.length); strcpy(ret.data,data); strcat(ret.data,other.data); ret.data[ret.length] = '\0'; return ret; } const String operator+(const char* other) { String ret("",length+strlen(other)); strcpy(ret.data,data); strcat(ret.data,other); ret.data[ret.length] = '\0'; return ret; } const String& operator+=(const String& other) { *this = operator+(other); return *this; } const String& operator+=(const char* other) { *this = operator+(other); return *this; } void assign(const char* data,int length = -1) //the same as operator=() but with length parameter { delete[] this->data; if(length == -1) { this->length = strlen(data); } else this->length = length; this->data = new char[this->length+1]; strncpy(this->data,data,this->length); this->data[this->length] = '\0'; this->data_size = this->length+1; } void crypt(const char* key) { unsigned int keylen = strlen(key); unsigned int k = 0; string reverser; for(unsigned int i=0;i<length;i++) { if(k == keylen) k = 0; data[i] = data[i] ^ key[k]; data[i] += key[k]; k++; } for(unsigned int i=0;i<length-2;i++) { char swap; swap = data[i]; data[i] = data[i+2]; data[i+2] = swap; } reverser = data; reverse(reverser.begin(),reverser.end()); strcpy(data,reverser.c_str()); } void decrypt(const char* key) { unsigned int keylen = strlen(key); unsigned int k = 0; string reverser = data; reverse(reverser.begin(),reverser.end()); strcpy(data,reverser.c_str()); for(unsigned int i=length-1;i>1;i--) { char swap; swap = data[i]; data[i] = data[i-2]; data[i-2] = swap; } for(unsigned int i=0;i<length;i++) { if(k == keylen) k = 0; data[i] -= key[k]; data[i] = data[i] ^ key[k]; k++; } } void reserve(unsigned int len) { length = len; data_size = len+1; delete[] data; data = new char[data_size]; memset(data,0,data_size); } int find(const char letter) { for(unsigned int i=0;i<length;i++) { if(data[i] == letter) return i; } return -1; } int find(const char* text) { char* pointer = strstr(data,text); if(pointer == 0) return -1; return pointer - data; } const char* c_str() const { if(data) return this->data; else return ""; } char* g_dat() //if needed, data can be modified { if(data) return this->data; // else return ""; //EXECPTION HIER EINFÜGEN } int size() { return this->data_size; } int len() { return this->length; } template <typename T> T convert(__int8 base = -1) { T output; stringstream wan; if(base == 16) wan << hex << data; else if (base == 8) wan << oct << data; else wan << data; wan >> output; return output; } }; template <class T,class Z> const Z convert(T in) { Z output; stringstream wan; wan << in; wan >> output; return output; } ostream& operator<<(ostream &os,const String &str) { os << str.data; return os; } istream& operator>>(istream &is,String &str) { string buffer; is >> buffer; str = buffer.c_str(); return is; } }
-
Musst du einen char* verwenden? Da es eine Informatik-Übung ist, vermutlich schon...
-
String() : length(0),data_size(0) { data = 0; // Initialisierungsliste... }String& operator=(......) { return *this; }Ansonsten sehe ich Codezeilen die öfters vorkommen. Die könntest du noch in eine Funktion auslagern, sodass du schlußendlich keine redundanten Codezeilen mehr hast.
-
Ok danke, ich werd euch dann sagen, welche Note ich bekommen habe ...
-
Nochmal zusammenfassend und ergänzend:
- Schau Dir nochmal Copy&swap für
operator=()an - Dazu: Was ist momentan mit Selbstzuweisung? (
String s = "bla"; s = s;) - Was passiert, wenn Du einen default-konstruierten String ausgibst?
- operator+() sollte freie Funktion sein
- ist diese doppelte Buchführung (
lengthu.length+1(aka.data_size)) notwendig? - Benutz duchgehend initialisierungslisten in den Konstruktoren (geht auch mit new[])
- zuviel const bei den Rückgabewerten
- zuwenig const in den Signaturen (
size(), find()...) - wenn Du eh binäre strings speichern willst, sind die str*-Funktionen aus C die falsche Wahl
- DRY!
- Nimm Überladung, bevor Du solche Krücken wie
if (length == -1)...benutzt - die Ein-/Ausgabeoperatoren müssen keine friends sein
- Schau Dir nochmal Copy&swap für