Frage zum guten Stil und Tests



  • Barados schrieb:

    Zum Thema Testen nocheinmal... Hat da jemand Vorschläge?

    Meine Erfahrungen beim Testen sind, dass man das nur mit der Zeit selbst lernt. Es gibt ne Menge Probleme in die man fallen kann, das schlimmste zum Beispiel, dass man selbst biased ist. Der Schreiber des Codes ist also der schlechteste Tester. Es gibt zwar Ansätze das Testen zu strukturieren, aber die funktionieren alle nicht.

    Ansonsten kommt es darauf an, was genau du programmierst. numerische Routinen oder Algorithmen testet man ganz anders als das korrekte Zusammenspiel von Objekten.



  • Meinst du manuelles Testen oder Unit Tests?



  • daddy_felix schrieb:

    Meinst du manuelles Testen oder Unit Tests?

    Ich sag einfach mal "Beides"...

    Ich umschreibe einfach mal was ich da bisher gemacht habe.
    Prinzipiell habe ich bisher maximal Testfunktionen geschrieben, welche dann auf den erwarteten Rückgabewert oder bestimmte veränderte Eigenschaften geprüft haben. Also ob sich eine Funktion so verhält wie man es erwartet. Das hab ich aber immer alles händisch gemacht, quasi dann bisserl output in eine Textdatei geschrieben und versucht das weitestgehend ordentlich durchzuformatieren. Ich bin mir sicher dass das auch noch anders geht^^

    Hier ist dann der bisherige Output meiner Übungsaufgabe:

    Statistics.h

    #ifndef STATISTICS_H_INCLUDED
    #define STATISTICS_H_INCLUDED
    
    #include <string>
    #include <vector>
    
    namespace dev
    {
    template<class T> T fromString(const std::string& s);
    template<class T> std::string toString(const T& t);
    
    typedef std::vector<int> IntVec;
    typedef std::vector<int>::iterator IntVecIt;
    
    class RandomVector
    {
    public:
        int operator [] (std::size_t idx);
        IntVec GetValues();
        std::string toString();
        void FillVec(int count);
        virtual ~RandomVector();
        RandomVector();
    private:
        IntVec* m_vecRandomness;
    
    };
    
    }
    
    #endif // STATISTICS_H_INCLUDED
    

    Statistics.cpp

    #include "Statistics.h"
    #include <iostream>
    #include <sstream>
    #include <stdexcept>
    #include <algorithm>
    
    #include <time.h>
    
    namespace dev
    {
    
    template<class T> std::string toString(const T& t)
    {
        std::ostringstream stream;
        stream << t << " ";
        return stream.str();
    };
    template<class T> T fromString(const std::string& s)
    {
        std::istringstream stream(s);
        T t;
        stream >> t;
        return t;
    };
    
    RandomVector::RandomVector()
    {
        m_vecRandomness = new IntVec();
    };
    
    RandomVector::~RandomVector()
    {
        if(m_vecRandomness != NULL)
            delete m_vecRandomness;
    };
    
    int RandomVector::operator [] (std::size_t idx)
    {
        return m_vecRandomness->at(idx);
    }
    
    IntVec RandomVector::GetValues()
    {
        if(m_vecRandomness == NULL)
        {
            std::ostringstream msg("Error in IntVec GetValues()", std::ostringstream::out);
            throw std::runtime_error(msg.str());
        }
        IntVec res;
        res.reserve(m_vecRandomness->size());
        (void) std::copy(m_vecRandomness->begin(),m_vecRandomness->end(),res.begin());
        return res;
    }
    
    std::string RandomVector::toString()
    {
        std::string msg = "";
        for(IntVecIt it = m_vecRandomness->begin(); it != m_vecRandomness->end(); it++)
        {
            msg.append(dev::toString(*it));
        }
        return msg;
    }
    
    void RandomVector::FillVec(int count)
    {
        if(count < 1)
            return;
        if(m_vecRandomness != NULL)
            delete m_vecRandomness;
        m_vecRandomness = new IntVec();
        m_vecRandomness->reserve(count);
        time_t t;
        time(&t);
        srand((unsigned int) (t*rand()));
        for(int i = 0; i < count; i++)
            m_vecRandomness->push_back(rand());
    };
    }
    

    Bitte macht mich auf etwaige Absonderlichkeiten aufmerksam.

    Grüße
    Bara

    PS: in der Header-Datei komm ich um das Include von vector und string ni drumrum...
    Forward-Deklaration von string wird ein riesiger Haufen und vector geht laut internet so oder so nicht...

    PSS: Mir kam da gerad noch eine Idee. Warum eigentlich nicht einfach

    class MyIntVec : public std::vector<int>
    {
    
    };
    

    und die um die benötigten Sachen erweitern?
    Ich würde halt die äußere Schnittstelle zerstören, aber hätte schon eine Masse an Funktionalität da.



  • Warum nutzt du einen Pointer als Member? 😮
    Edit: Zu viel. Ich schreib das mal neu, das geht schneller. 😉



  • cooky451 schrieb:

    Warum nutzt du einen Pointer als Member? 😮

    Common sense in meiner alten Firma.

    Und genau deshalb hab ich ja den Thread hier aufgemacht 😃

    verwirrter Geist schrieb:

    Lernen heisst sich einzugestehen, dass man nicht soooooooooo viel wissen tun tut...



  • Was auch immer diese Klasse bringen soll..

    class random_number_vector
    {
    	std::vector<int> numbers_;
    
    public:
    	random_number_vector(std::size_t amount)
    		: numbers_(amount)
    	{
    		std::generate(numbers_.begin(), numbers_.end(), std::rand);
    	}
    	int operator [] (std::size_t index)
    	{
    		return numbers_[index];
    	}
    };
    

    Fertig. Ob du .at() oder [] möchtest sei dir überlassen, aber meiner Meinung nach sind ungültige Indexzugriffe eindeutig Programmierfehler, da arbeite ich lieber mit Dingen die nur im Debugmode aktiv sind. *

    Alle anderen Funktionen (insbesondere to_string und Ähnliches) sollten freie Funktionen sein, sie gehören nicht wirklich zur Funktionalität der Klasse.
    Und warum hast du deinen Destruktor virtual gemacht? Willst du von der Klasse erben?

    * Die Entscheidung ist übrigens nicht ganz so einfach. In einer idealen Welt hast du im Releasemodus keine Bugs mehr, musst also auch nur auf runtime Fehler reagieren. Nun ja, die ideale Welt haben wir wohl noch nicht, daher ist das eine kleine Gradwanderung zwischen Performance und ordentlichen Fehlermeldungen auch beim Nutzer.



  • Hallo nochmal,

    um bloss kurz meinen letzten Gedanken zuende zu spinnen, hier eine "angepasste Version"... Ach ja. Die Klasse ist aus einem kurzen Gedankenspiel entstanden, wo es um etwas anderes ging. Halt reiner Übungszweck.

    class MyIntVec : public std::vector<int>
    {
        void FillVec(int count)
        {
            if(count < 1)
                return;
            this->reserve(count);
            time_t t;
            time(&t);
            srand((unsigned int) (t*rand()));
            for(int i = 0; i < count; i++)
                this->push_back(rand());
        };
        std::string toString()
        {
            std::string msg = "";
            for(dev::IntVecIt it = this->begin(); it != this->end(); it++)
            {
                msg.append(dev::toString(it));
            }
            return msg;
        }
    };
    

    Mit freien Funktionen kann ich mich eigentlich nicht wirklich anfreunden. Ich hab sie hier zwar selbst (toString() und fromString()) aber habe lieber die Zugehörigkeit zu einer Klasse.

    Der virtuelle Destruktor bringt wirklich nichts, aber ich habe virtual einfach mal hingeschrieben um mir die Möglichkeit zu erhalten... Ebenfalls eine schlechte Angewohnheit, quasi...

    Ich danke dir jedenfalls herzlich für deine Geduld, auch wenn mich manche deiner Sätze denken lassen, dass du hier das ein oder andere Dioptrin verlierst 😃

    Grüße
    Bara

    PS: Ich seh schon dass ich mir die "std" noch genauer ansehen muss. std::generate is ja sehr nett.

    -->

    class MyIntVec : public std::vector<int>
    {
    	MyIntVec(std::size_t amount)
    	{
    		FillVec(amount);
    
    	}
        void FillVec(std::size_t count)
        {
        	clear();
            reserve(count);
            std::generate(begin(), end(), std::rand);
        };
        std::string toString()
        {
            std::string msg = "";
            for(dev::IntVecIt it = begin(); it != end(); it++)
            {
                msg.append(dev::toString(it));
            }
            return msg;
        }
    };
    


  • Na ja, von std::vector zu erben ist nur bedingt eine gute Idee. Guck dir das mal an:

    struct my_struct : public std::vector<int>
    {
    	~my_struct()
    	{
    		std::cout << "Yay\n"; // Wird nie ausgegeben
    	}
    };
    
    int main()
    {
    	std::vector<int>* p = new my_struct;
    	delete p;
    }
    

    Wenn du das machst, dann private erben. Dann ist das halt Implementierungsdetail. (Und clear() musst du nicht aufrufen vor resize())



  • Barados schrieb:

    PS: Ich seh schon dass ich mir die "std" noch genauer ansehen muss. std::generate is ja sehr nett.

    trolololol



  • Ergo vom vector nur erben, wenn ich Funktionalitäten hinzufügen möchte. Erweiterung um dynamisch erzeugte Member-Variablen sollten vermieden werden, da man nicht hinter sich aufräumen kann (Destruktor ni virtual)?

    Grüße
    Bara

    314159265358979 schrieb:

    Barados schrieb:

    PS: Ich seh schon dass ich mir die "std" noch genauer ansehen muss. std::generate is ja sehr nett.

    trolololol

    I w1sh 1 w0uld b3 a5 l33t a5 U



  • Barados schrieb:

    I w1sh 1 w0uld b3 a5 l33t a5 U

    Ich wollte damit auf nicht sehr hilfreiche Weise sagen, dass es sehr, sehr traurig ist, wenn du nichts aus dem Standard-Namespace kennst. Dir fehlen damit massive Grundlagen und dein Code hat wohl bisher wenig mit C++ zu tun. Mein Rat an dich: Such dir ein gutes Buch (in den FAQs gibts einige Empfehlungen) und lerne C++ von Grund auf mithilfe der Standardbibliothek neu.



  • Da ich am besten im Parsen von Sätzen bin, habe ich wirklich nicht verstanden was du ausdrücken wolltest.

    Dass mir Grundlagen fehlen ist mir bewußt und wenn du den Thread gelesen hättest, wäre dir eine gewisse Lernbereitschaft nicht verborgen geblieben...

    BACK2TOPIC

    Bara



  • Barados schrieb:

    class MyIntVec : public std::vector<int>
    {
    	MyIntVec(std::size_t amount)
    	{
    		FillVec(amount);
    
    	}
        void FillVec(std::size_t count)
        {
        	clear();
            reserve(count);
            std::generate(begin(), end(), std::rand);
        };
        std::string toString()
        {
            std::string msg = "";
            for(dev::IntVecIt it = begin(); it != end(); it++)
            {
                msg.append(dev::toString(it));
            }
            return msg;
        }
    };
    
    • reserve willst du nicht, sondern resize .
      - da ist ein unnötiges Semikolon hinter der Methoden FillVec
    • FillVec könnte auch einfach fill heißen
    • fill trifft es nicht, es müsste eher fillRandom oder so heißen
    • toString soll die Zahlen einfach aneinander kleben?
      - der Iterator wird nicht dereferenziert
      - freie Funktionen wären weniger sinnlos und verwirrend
      - die Konstruktoren des vector<int> gehen verloren


  • 314159265358979 schrieb:

    Barados schrieb:

    I w1sh 1 w0uld b3 a5 l33t a5 U

    Ich wollte damit auf nicht sehr hilfreiche Weise sagen, dass (...)

    Wenigstens ist dir jetzt klar dass es nicht hilfreich ist/war.
    Hat ja bloss ein paar Jahre gedauert bis du so weit warst.

    In weiteren 2-3 Jahren schaffst du es dann vielleicht gleich was sinnvolles/verständliches/hilfreiches zu schreiben, anstatt erstmal blöd zu melden. Das (blöd melden) ist nämlich noch weniger hilfreich, als wenn du einfach nix schreiben würdest.



  • Sorry, aber nach dem Satz vom TE denke ich einfach nur noch trolololol 🙄

    Und anstatt Sätze zu bringen wie "Hat ja bloss ein paar Jahre gedauert" und "In weiteren 2-3 Jahren schaffst du es dann vielleicht" hättest du dir deinen Post auch gleich sparen können.



  • Also ich fand den Post sinnvoll, einfach weil es mir ermöglicht, einmal selbst tief durchzuatmen.

    Es ist gar nicht so ungewöhnlich, dass Programmierer die std-lib nicht gut kennen. Stroustrup hat das in seinem Paper über den Aufbau seiner Programmiervorlesung gut herausgearbeitet. Es ist ein strukturelles Problem der Art wie C++ vermittelt wird, seien es Bücher, Tutorials oder Vorlesungen.



  • 314159265358979 schrieb:

    Sorry, aber nach dem Satz vom TE denke ich einfach nur noch trolololol 🙄

    Darfst du gerne. Hinschreiben musst du es aber nicht. Und wenn es denn sein muss, dann wenigstens mit Erklärung.

    Und anstatt Sätze zu bringen wie "Hat ja bloss ein paar Jahre gedauert" und "In weiteren 2-3 Jahren schaffst du es dann vielleicht" hättest du dir deinen Post auch gleich sparen können.

    Wenn ich so wie du drauf wäre, müsste ich unter ca. 30% deiner Beiträge Dinge wie "Halt doch endlich dein Maul du Vollspast" schreiben. Ohne weitere Erklärung.
    Soll ich das in Zukunft so machen?



  • Mach doch, dann verschwindest du wenigstens schnell 🤡



  • Warum sollte ich verschwinden, dich hat man ja auch noch nicht entsorgt 🤡

    EDIT: die 30% sind stark übertrieben, in letzter Zeit postest du viel weniger Schrott. Wäre aber schön wenn du das noch etwas weiter ausbauen könntest.
    EDIT2: nachdem ich jetzt in den Genuss des ">>" Threads gekommen bin muss ich das "viel" wieder streichen, hihi.



  • otze schrieb:

    Es ist gar nicht so ungewöhnlich, dass Programmierer die std-lib nicht gut kennen. Stroustrup hat das in seinem Paper über den Aufbau seiner Programmiervorlesung gut herausgearbeitet. Es ist ein strukturelles Problem der Art wie C++ vermittelt wird, seien es Bücher, Tutorials oder Vorlesungen.

    Ich habe als Programmierer in einer Firma angefangen in der so ziemlich "REIN" mit der MFC programmiert wurde. Da war ich eigentlich der erste, der auch mal Sachen aus der std-lib eingebaut hat. Die letzten Jahre habe ich wiederum nur C# benutzt, wo die Standardlib ja sogesehen nicht vorhanden oder unendlich gross ist (ich weiss, ist so auch nicht 101% richtig).

    Und wie ich schon schrieb: ich weiss dass ich Nachholbedarf habe und will daran ja auch arbeiten. Ich denke dass ist auch sehr deutlich geworden. Ich denke dafür ist so ein Forum auch da. Prinzipiell hat sich meine Übungsklasse nun ja auch schonmal von einem riesigen Haufen in einen 10-Zeiler reduziert, was ich als Lernerfolg sehe.

    Grüße
    Bara 🙂


Anmelden zum Antworten