C++ ungeeignet für 64K Demos?



  • Gut dann hab ich jetzt paar fragen:

    - Wie sähe so ein überladener new-operator aus? Wieso sollte man den überhaupt überladen?

    - Sollte man viel mit new arbeiten oder lieber statische-arrays schreiben? also char buffer[32];?

    - Warum keine Exceptions?

    - wie fängt man am beste für eine eigene string-klasse an? welche features sollten umbedingt rein und welche nicht?



  • ..................... schrieb:

    - Sollte man viel mit new arbeiten oder lieber statische-arrays schreiben? also char buffer[32];?

    Statische Variablen sind schneller erstellt; derart kleine Arrays verursachen auch bestimmt keinen Stacküberlauf.

    ..................... schrieb:

    - Warum keine Exceptions?

    Weil die Überprüfung auf Exceptions deinen Code aufbläht.



  • audacia schrieb:

    ..................... schrieb:

    - Sollte man viel mit new arbeiten oder lieber statische-arrays schreiben? also char buffer[32];?

    Statische Variablen sind schneller erstellt; derart kleine Arrays verursachen auch bestimmt keinen Stacküberlauf.

    Und wie ist das mit der größe?

    Also ich glaube es gibt sicherlich einen unterschied in der größe der datei wenn ich:

    char buffer[2048]; schreibe als

    char *buffer = new char[2048];



  • ..................... schrieb:

    - Wie sähe so ein überladener new-operator aus?

    void* operator new(size_t size){
       return HeapAlloc(GetProcessHeap(),0,size);
    }
    void operator delete(void* p){
       HeapFree(GetProcessHeap(),0,p);
    }
    

    Wieso sollte man den überhaupt überladen?

    weil bei windows ein kleines speichermanagement eingebaut ist. es ist langsam und so, kein vergleich zum mitgelieferten operator new. aber es ist extrem wenig code für's eigene programm.

    - Sollte man viel mit new arbeiten oder lieber statische-arrays schreiben? also char buffer[32];?

    statische arrays sind noch billiger. zum freigeben braucht man gar keinen code und zum anlegen muß nur der stackpointer inkrementiert werden. außerdem werden statische arrays viel schneller angelegt.
    aber was ist, wenn man die größe nicht zur compilezeit kennt oder wenn man innerhalb einer funktion speicher anlegen möchte und den speicher zurückgebenb will? da muß schon new her.

    - Warum keine Exceptions?

    das exception-handling macht beim MinGW schon allein 20k aus. das kann sich natürlich keiner leisten. ok, mal alternativen angucken.
    a) kleineres exception-handlich schreiben.
    ist sehr schwirig, weil a viel compilermagie dabei ist
    b) das in den microsoft-dlls benutzen
    keine ahnung, ob das erlaubt ist. ich vermute mal: nein.
    c) fehler wie gewohnt in c hochgeben.
    naja, bei mini-programmen ist das billiger als exception-handling. bei fetteren programmen wird dann das exception-handling billiger.
    d) einfach alle fehler ignorieren!
    yeah, that's it! wenn der user keine soundkarte hat oder directx nicht hat, kackt das prog einfach ab. das scheint mir ideal für 64k-demos.

    - wie fängt man am beste für eine eigene string-klasse an?

    so:

    class String{
       char* date;
    public:
       String(char const* d=""){
          data=new char[strlen(d)+1];
          strcpy(d,data);
       }
    }
    

    welche features sollten umbedingt rein und welche nicht?

    je nach dem, was die anwendung machen soll. strings könnten zum beispiel welche sein, die keinen besitz am speicher haben

    class String{
       char const* date;
    public:
       String(char const* d=""){
          data=d;
       }
       friend bool operator==(string const a,string const b){
          return strcmp(a.data,b.data)==0;
       }
    }
    

    und die nur dafür sorgen, daß man mit char* ein wenig leichter umgehen kann und einen eigenen namen hat. das wäre zunächst mein weg, denn ich fürchte, außer ein paar dateinamen und so würden strings nicht viel verwendet werden. und wieder der vorteil, ich kann auch ganz am ende, wenn ich feststelle, daß ich doch andere strings hätte nehmen sollen, sie an einer zentralken stelle (der String.cp) verändern und das ganze programm hat was davon.

    sie könnten auch wie die klasse zuvor sich immer eine kopie der daten machen und dann konsequenterweise im destruktor die kopie löschen. sie könnten auch in einer globalen hashtable ihre daten eintragen und nur indizes auf die hashtable führen.



  • @volkard
    Vielen Dank! Doch noch eine frage zur string-klasse: Du initialisierst mit new, aber gibst den speicher nicht mehr frei? Also das du von Fehlerbehandlung in 64K-Demos nichts hälst hast du ja erklärt aber Fehlermachung? :D:D:D



  • @.........................:

    Deine Frage war:

    .............. schrieb:

    - wie fängt man am beste für eine eigene string-klasse an?

    , und genau darauf hat Volkard geantwortet.



  • audacia schrieb:

    @.........................:

    Deine Frage war:

    .............. schrieb:

    - wie fängt man am beste für eine eigene string-klasse an?

    , und genau darauf hat Volkard geantwortet.

    Das ist doch kein Argument etwas anzufangen und halb fertig liegen lassen. Das ist eine Potenzielle Fehlerquelle!



  • .................. schrieb:

    Das ist doch kein Argument etwas anzufangen und halb fertig liegen lassen. Das ist eine Potenzielle Fehlerquelle!

    erhoffst du dir, daß ich eine fertige string-klasse baue? dazu hatte ich gerade keine lust.



  • volkard schrieb:

    weil bei windows ein kleines speichermanagement eingebaut ist. es ist langsam und so, kein vergleich zum mitgelieferten operator new. aber es ist extrem wenig code für's eigene programm.

    Das mitgelieferte new ruft über Umwege schon HeapAlloc auf.

    volkard schrieb:

    statische arrays sind noch billiger. zum freigeben braucht man gar keinen code und zum anlegen muß nur der stackpointer inkrementiert werden. außerdem werden statische arrays viel schneller angelegt.

    Statische Arrays beeinflussen den Stackpointer nicht. Das Anlegen geschieht, bevor main aufgerufen wird



  • vollkard schrieb:

    Das mitgelieferte new ruft über Umwege schon HeapAlloc auf.

    oder besser VirtualAlloc. mir geht es darum, die umwege wegzumachen. die umwege sind zum beispiel ein small object allocator, den man in c++ sinnvollerweise davorsetzt, um mehr speed zu bekommen. siehe modern c++ design. in der 64k-demo spare ich mir einfach den ganzen speed-bringenden umweg und mache ein lahmes, aber kleines new.

    vollkard schrieb:

    Statische Arrays beeinflussen den Stackpointer nicht. Das Anlegen geschieht, bevor main aufgerufen wird

    "statisch" hat mehr als eine bedeutung, scheint mir. ich meinte hier nur statisch im gegensatz zu dynamisch. mit dynamisch bezeichnet man speicher, den man sich zur laufzeit über aufrufe von new, malloc und so holt und dessen größe duchaus erst zur laufzeit bekannt sein kann. mit statisch bezeichnet man speicher, der per definition da ist, dessen größe erst zur compilezeit bekannt ist.
    in diesem sinne ist ein lokales array durchaus statisch.

    du scheinst das schlüsselwort static zu meinen. also im prinzip globalen variablen. der ist in der tat noch billiger, was die code-größe angeht.



  • @TGGC_work
    ich erteile dir hiermit virtuelles hausverbot für diesen thread. du darfst hier nicht mehr posten.
    ich logge, wie oft ich postings von dir lösche und behalte mir vor, dich bei zuwiderhandlung kostenpflichtig abzumahnen.



  • volkard schrieb:

    @TGGC_work
    ich erteile dir hiermit virtuelles hausverbot für diesen thread. du darfst hier nicht mehr posten.
    ich logge, wie oft ich postings von dir lösche und behalte mir vor, dich bei zuwiderhandlung kostenpflichtig abzumahnen.

    Gilt das für alle TGGC's?

    Bye, TGGC (Wähle deine Helden)



  • TGGC´ schrieb:

    Gilt das für alle TGGC's?

    Es gilt für alle, die, obwohl ich ein Posting gelöscht habe, es wieder einstellen. Im Falle dieses Störers dürften es an die 100 Löschungen schon sein. Und natürliche bedarf es keiner Warnung, bevor ich rechliche Schritte einleite, aber ich hoffe, er hört auf, ohne daß ich ganz fies werden muß.



  • volkard schrieb:

    .................. schrieb:

    Das ist doch kein Argument etwas anzufangen und halb fertig liegen lassen. Das ist eine Potenzielle Fehlerquelle!

    erhoffst du dir, daß ich eine fertige string-klasse baue? dazu hatte ich gerade keine lust.

    Das brauchst du auch nicht, mein Süßer. Das mach' ich schon für dich:

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    class String
    {
      public:
    	// Konstruktoren
    	String();
    	String(const char *const);
    	String(const String &);
    	~String();
    
    	// Überladene Operatoren
    	char & operator[](int offset);
    	char operator[](int offset) const;
    	String operator+(const String&);
    	void operator+=(const String&);
    	String & operator= (const String &);
    
    	// Allgemeine Zugriffsoperatoren
    	int GetLen()const { return itsLen; }
    	const char * GetString() const { return itsString; }
    	// static int ConstructorCount;
    
      private:
    	String (int);         // Privater Konstruktor
    	char * itsString;
    	int itsLen;
    
    };
    
    // Standardkonstruktor erzeugt String von 0 Bytes Länge
    String::String()
    {
    	itsString = new char[1];
    	itsString[0] = '\0';
    	itsLen=0;
    	// cout << "\tString-Standardkonstruktor\n";
    	// ConstructorCount++;
    }
    
    // Privater (Hilfs-) Konstruktor, nur von Klassen-
    // methoden zum Erzeugen eines neuen Strings der
    // erforderlichen Größe verwendet. Mit Null gefüllt.
    String::String(int len)
    {
    	itsString = new char[len+1];
    	int i;
    	for (i = 0; i<=len; i++)
    		itsString[i] = '\0';
    	itsLen=len;
    	// cout << "\tString(int)-Konstruktor \n";
    	// ConstructorCount++;
    }
    
    String::String(const char * const cString)
    {
    	itsLen = strlen(cString);
    	itsString = new char[itsLen+1];
    	int i;
    	for (i = 0; i<itsLen; i++)
    		itsString[i] = cString[i];
    	itsString[itsLen]='\0';
    	// cout << "\tString(char*)-Konstruktor\n";
    	// ConstructorCount++;
    }
    
    String::String (const String & rhs)
    {
    	itsLen=rhs.GetLen();
    	itsString = new char[itsLen+1];
    	int i;
    	for ( i = 0; i<itsLen;i++)
    		itsString[i] = rhs[i];
    	itsString[itsLen] = '\0';
    	// cout << "\tString(String&)-Konstruktor\n";
    	// ConstructorCount++;
    }
    
    String::~String ()
    {
    	delete [] itsString;
    	itsLen = 0;
    	// cout << "\tString-Destruktor\n";
    }
    
    // Gleich-Operator, gibt vorhandenen Speicher frei,
    // kopiert dann String und Größe
    String& String::operator=(const String & rhs)
    {
    	if (this == &rhs)
    		return *this;
    	delete [] itsString;
    	itsLen=rhs.GetLen();
    	itsString = new char[itsLen+1];
    	int i;
    	for (i = 0; i<itsLen;i++)
    		itsString[i] = rhs[i];
    	itsString[itsLen] = '\0';
    	return *this;
    	// cout << "\tString-Operator=\n";
    }
    
    // Nicht konstanter Offset-Operator, gibt Referenz
    // auf Zeichen zurück, das sich damit ändern
    // läßt!
    char & String::operator[](int offset)
    {
    	if (offset > itsLen)
    		return itsString[itsLen-1];
    	else
    		return itsString[offset];
    }
    
    // Konstanter Offset-Operator für konstante
    // Objekte (siehe Kopierkonstruktor!)
    char String::operator[](int offset) const
    {
    	if (offset > itsLen)
    		return itsString[itsLen-1];
    	else
    		return itsString[offset];
    }
    
    // Erzeugt einen neuen String durch Anfügen des
    // aktuellen Strings an rhs
    String String::operator+(const String& rhs)
    {
    	int  totalLen = itsLen + rhs.GetLen();
    	int i,j;
    	String temp(totalLen);
    	for (i = 0; i<itsLen; i++)
    		temp[i] = itsString[i];
    	for (j = 0; j<rhs.GetLen(); j++, i++)
    		temp[i] = rhs[j];
    	temp[totalLen]='\0';
    	return temp;
    }
    
    // Ändert aktuellen String, gibt nichts zurück
    void String::operator+=(const String& rhs)
    {
    	int rhsLen = rhs.GetLen();
    	int totalLen = itsLen + rhsLen;
    	int i,j;
    	String  temp(totalLen);
    	for (i = 0; i<itsLen; i++)
    		temp[i] = itsString[i];
    	for (j = 0; j<rhs.GetLen(); j++, i++)
    		temp[i] = rhs[i-itsLen];
    	temp[totalLen]='\0';
    	*this = temp;
    }
    
    // int String::ConstructorCount = 0;
    


  • bei mir bringt der überladene new operator weder vor noch nach dem upx'en etwas. 😞
    wobei ich für meine kleinen 64k demos bisher nie new benutzte und stringklassen emm.. naja... emm... wozu strings? hab ich auch noch nie benutzt.

    btw. sind bei 64k demos externe system-dlls die jeder haben sollte erlaubt, sonst wäre dx und oGL auch nicht zugelassen 🙂

    rapso->greets();



  • volkard schrieb:

    und wie sehen diese template-tricks aus?

    schattig. du mußt halt genau wissen, was du machst (auch immer wieder den erzeugten asm-code angucken, um ein gefühl dafür zu kriegen, was der compiler draus macht).

    Oh, da hab ich mich ein wenig vertan. Template-Tricks helfen ja eher Binarygröße für Speed einzutauschen durch Loopunrolling und Inlining. Naja, da muss man wohl mal ein wenig rumtesten, was man damit rausholen kann.



  • ich seh trotzdem nicht, was compileroptionen wie loop unrolling und sprachmerkmale wie "inline" mit c++ templates zu tun haben sollen...

    die stringklasse war sehr lehrreich. ich werd sie mir auch mal zerlegen und untersuchen.



  • c.rackwitz schrieb:

    ich seh trotzdem nicht, was compileroptionen wie loop unrolling und sprachmerkmale wie "inline" mit c++ templates zu tun haben sollen...

    loop-Unrolling kannst du über ein entsprechendes Template-Metaprogramme z.B. erzwingen.
    Die inline-Expansion einer Funktion kann z.B. dank eines Templates überhaupt erst möglich werden. Beispiel: qsort vs. std::sort.





  • hier ein kleines Beispiel:

    #include <iostream>
    
    using namespace std;
    
    template<unsigned int N>
    inline void schreibNMal(const char s[])
    {	
    	schreibNMal<N-1>(s);
    	cout<<N<<": "<<s;
    }
    
    template<>
    inline void schreibNMal<1>(const char s[])
    {
    	cout<<"1: "<<s;
    }
    
    int main()
    {
    	schreibNMal<5>("unroll ohne compiler optionen\n");
    	cin.get();
    }
    

Anmelden zum Antworten