Problem mit Software Architektur (C++)



  • Ishildur schrieb:

    @Nukularfüsiker
    Seit wann kann ein linker Pure Virtual Functions entfernen?

    Das Warum überblicke ich gerade auch nicht, aber das ist es, was die Meldung besagt.

    Ishildur schrieb:

    @asc
    Welche Warnung meinst du konkret, die man nicht einfach ausschalten sollte?

    Also ich würde ja sagen man sollte zumindest die nicht ausschalten, deren Sinn man nicht genau verstanden hat. Und das ist bei dir bei einigen der genannten der Fall.

    Ishildur schrieb:

    #pragma warning(disable:4127) // conditional expression is constant [while(true)]
    

    Oft hat man keine Ahnung, wie oft eine schleife durchlaufen wird, sie wird mit einem break verlassen.

    for(;;) bringt keine Warnung.

    #pragma warning(disable:4482) // nonstandard extension used: enum
    

    Ja genau, ich darf keine enums benutzen

    Du hast sicher sowas gemacht:

    int foo = Enum::Wert
    

    Es ist aber nicht erlaubt, Enum:: zu spezifizieren.

    #pragma warning(disable:4706) // assignment within conditional expression
    

    Muss ich die Methode wie strlen usw. 2mal aufrufen, einmal für den Test und dann noch einmal für die effektive Zuweisung (genau!)

    Die Erklärung verstehe ich nicht. Und auch nicht, was strlen in einem C++-Program verloren hat.

    #pragma warning(disable:4715) // not all control paths return a value
    

    Methoden, welche einen return value != void haben und eine exception werfen, werden nicht mehr kompiliert.

    Zeig mal ein Beispiel.

    #pragma warning(disable:4701) // potentially uninitialized local variable used
    

    Vielfach hat man variablen, welche man mit Werten aus einer Datei oder anderen Datenquellen füllt, diese dann vorher noch explizit mit null zu füllen, nur um sich gleich anschliessend auf der nächsten Zeile wieder zu überschreiben.

    Das sollte eigentlich keine Warnung verursachen. Zeig mal ein Beispiel.

    #pragma warning(disable:4238) // nonstandard extension used : class rvalue used as lvalue
    

    SetVector(&Vector3(0.0f,0.0f,0.0f))
    Was soll daran falsch sein?

    Ein rvalue hat nun mal keine Adresse.

    #pragma warning(disable:4996) // 'stricmp': The POSIX name for this item is deprecated.
    

    Und wie lautet der richtige Name? Habe ich nirgends gefunden...

    Eigentliches Problem: du benutzt C-Funktionen in C++.



  • okok, ich glaube wir schweifen ein wenig ab. Guter Stiel / Schlechter Stiel, C in C++. Also nur ganz kurz, oft hat man ja bestehenden Code oder auch externe Dinge im Source vorliegen und direkt hineinkompiliert werden müssen. Zu den rvalues. Jeder der schon mal mit der DirectX Extension Library zu tun hatte, wird das Problem kennen 😉

    Nein viel interessanter ist nun glaube ich schon der Linkerfehler...



  • Ishildur schrieb:

    okok, ich glaube wir schweifen ein wenig ab. Guter Stiel / Schlechter Stiel, C in C++.

    Also da geht es ja nicht nur um Stilfragen, sondern um handfeste Fehler, die du kurzerhand mit

    disable stupid and useless compiler - warnings
    

    abgewürgt hast. Die kommen irgendwann zurück und beißen dich in den Allerwertesten. Wird sich noch zeigen, wer stupid und useless war 🙂

    Zu den rvalues. Jeder der schon mal mit der DirectX Extension Library zu tun hatte, wird das Problem kennen 😉

    Nee, erklär mal.



  • Ishildur schrieb:

    @Nukularfüsiker
    Seit wann kann ein linker Pure Virtual Functions entfernen?

    Wenn sie nie aufgerufen werden - warum nicht?

    Ein minimales kompilierbares Beispiel wäre halt super. Die Warnung heisst ja nur, dass dead code eliminiert wurde. Jetzt müsste man rausfinden warum es dead code ist 😉

    und zu dem deaktivieren der warnungen sag ich mal lieber nix...



  • Zu den rvalues. Jeder der schon mal mit der DirectX Extension Library zu tun hatte, wird das Problem kennen 😉

    Viele DirectX Funktionen nehmen einen Parameter als Zeiger, welcher dann aber innerhalb der Funktion kopiert wird. Eine Referenz wäre hier IMHO eben schöner, aber eben, man verwendet ja auch Code, der nicht von einem selbst ist:

    Beispiel:

    D3DXVECTOR3 out;
    D3DXMatrixLookAtLH(&out,&D3DXVECTOR3(0.0f,1.0f,0.0),&D3DXVECTOR3(0.0f,0.0f,0.0f),&D3DXVECTOR3(0.0f,1.0f,0.0f));
    

    Mit dieser Warnung aktiviert muss man dies dann folgendermassen umschreiben:

    D3DXVECTOR3 out;
    D3DXVECTOR3 eye;
    D3DXVECTOR3 at;
    D3DXVECTOR3 up;
    D3DXMatrixLookAtLH(&out,&eye,&at,&up);
    

    Das mag zwar auf den ersten Blick sogar schöner sein, aber nicht mehr, wenn man 100erte solcher Funktionen aufrufen muss.

    Parameter aus dem Interface rausschmeißen, wenn diese nicht gebraucht werden.

    Dazu sag ICH jetzt mal nichts....

    Aber wie gesagt, ich möchte mich hier nicht streiten. Es wäre ja noch was ganz anderes gewesen, wenn einfach jemand freundlich nach dem WARUM gefragt hätte und sich anschliessend erst mal meine Argumentation angehört hätte, bevor drauf los gewettert wird, aber na gut...


  • Mod

    Es ist aber schon so, dass Warnungen in der Regel gleich einem Fehler sind oder zumindest gleich einem potentiellen Fehler. Man schaltet eine Warnung nur dann bewusst aus, wenn man genau verstanden hat, warum diese Warnung ausgegeben wird und sich ganz sicher ist, dass diese Gründe in diesem besonderen Fall (jeden Fall einzeln prüfen!) nicht vorliegen.

    Dein DirectX Interface ist ein schönes Beispiel, wo man die Warnung ruhigen Gewissens ausschalten darf, sofern man ganz sicher weiß, dass in der Funktion eine Kopie des Pointees erstellt wird, so dass man hinterher nicht auf nicht-existierende Objekte zeigt. In jedem anderen Fall deutet die Warnung aber auf einen schweren Fehler hin und man sollte unverzüglich den Grund für die Warnung abstellen und nicht die Warnung selbst.



  • Ishildur schrieb:

    Parameter aus dem Interface rausschmeißen, wenn diese nicht gebraucht werden.

    Dazu sag ICH jetzt mal nichts....

    Den Namen des Parameters rauswerfen:

    int foo(int a, char) {
      return a;
    }
    

    und schon ist die warnung weg...



  • @SeppJ
    Ja ich stimme dir bei diesem Beitrag bei, aus diesem Grund habe ich dem Compiler auch gesagt, das Warnungen als Fehler geanded werden sollen. Aber du kannst dir vorstellen, dass es einfach extrem nervig ist, wenn der Code dann ständig wegen solchen Sachen (wo man ganz genau weiss, dass es in diesem Fall kein Problem ist) nicht mehr kompiliert. Daher habe ich diese ausgeschaltet und schalte sie erst wieder ein, wenn ein Modul abgeschlossen ist (und prüfe da jeden einzelen Fall noch einmal).

    @Shade of Mine
    Danek für den Tipp, das habe ich nicht gewusst. 🙂



  • @Shade of Mine
    Habe das schnell ausprobiert, funktioniert, aber findest du das wirklich schön?

    void MyInterfaceMethod(float32 A,float32,float32,uint16,int64 E){
    }
    

    Vielfach hat man ja auch die Situation, dass man eine Funktion (bspw. fürs Prototyping noch nicht vollständig implementiert (spricht noch nicht alle Parameter interpretiert) oder dass man sich einen zusätzlichen Parameter definiert (reserviert), bei dem man noch nicht weis, wofür man ihn irgendwann benutzen könnte, aber dass man die Funktion eben erweitern könnte, ohne die Interfaces verändern zu müssen.



  • @Janjan

    Schlechter Stil. Immer komplette Pfade haben.

    float32 divide(float32 A,float32 B){
     if(B == 0.0f) throw DivisionException();
     else return A/B;
    }
    

    Kannst du mir zeigen, wie du das so machst, dass da keine C4715 Warnung kommt?



  • Ishildur schrieb:

    Vielfach hat man ja auch die Situation, dass man eine Funktion (bspw. fürs Prototyping noch nicht vollständig implementiert (spricht noch nicht alle Parameter interpretiert) oder dass man sich einen zusätzlichen Parameter definiert (reserviert), bei dem man noch nicht weis, wofür man ihn irgendwann benutzen könnte, aber dass man die Funktion eben erweitern könnte, ohne die Interfaces verändern zu müssen.

    Und in so einen Fall weisst du schon dass der Parameter numberOfElements oder so heissen wird?

    Du lässt den Namen ja in der Implementierung weg - in der Interface Definition darf ja ruhig ein Name stehen...

    Und was du in der Implementierung machst ist ja dein privat vergnügen...



  • Ishildur schrieb:

    @Janjan

    Schlechter Stil. Immer komplette Pfade haben.

    float32 divide(float32 A,float32 B){
     if(B == 0.0f) throw DivisionException();
     else return A/B;
    }
    

    Kannst du mir zeigen, wie du das so machst, dass da keine C4715 Warnung kommt?

    float32 divide(float32 A,float32 B){
     if(B == 0.0f) throw DivisionException();
     return A/B;
    }
    


  • Ishildur schrieb:

    @Janjan

    Schlechter Stil. Immer komplette Pfade haben.

    float32 divide(float32 A,float32 B){
     if(B == 0.0f) throw DivisionException();
     else return A/B;
    }
    

    Kannst du mir zeigen, wie du das so machst, dass da keine C4715 Warnung kommt?

    float32 divide(float32 A,float32 B)
    {
        if(std::fabs(B) == 0.0f)
            throw DivisionException();
    
        return A/B;
    }
    


  • Wo ist der Unterschied? Ausser dass das Beispiel ohne "else" meiner Meinung nach weniger intuitiv lesbar ist?



  • Ishildur schrieb:

    Wo ist der Unterschied?

    Es gibt keine Warnung.



  • Also schreibe ich weniger intuitiven Code, nur damit keine MS Compiler spezifische Warnung erscheint? :p



  • Ishildur schrieb:

    Also schreibe ich weniger intuitiven Code, nur damit keine MS Compiler spezifische Warnung erscheint? :p

    Das else ist unnötig. oder schreibst du auch

    if(error1) throw error1();
    else if(error2) throw error2();
    else if(error3) throw error3();
    

    ?

    nein.

    den code immer links halten. dadurch reduziert sich die komplexität des codes.

    fehler werden mit if abgefangen und die funktion beendet. der normale kontrollfluss der funktion findet also auf der "linkesten ebene" statt.


  • Mod

    float32 divide(float32 a,float32 b){
      return b != 0 ? a / b : throw DivisionException();
    }
    


  • Ishildur schrieb:

    @asc
    Welche Warnung meinst du konkret, die man nicht einfach ausschalten sollte?

    Wie ich sehe, hat dein Compiler einige starke Mankos (z.B. 4715). Einige andere Warnungen kann man dadurch los werden, in dem man bei seinen Code kleine Anpassungen macht, und damit auch verdeutlicht was gemeint ist. Unabhängig davon halte ich dennoch ein allgemeines Abschalten für grundsätzlich falsch, da man dann auch nicht die Fälle wahrnimmt, in denen die Warnungen durchaus berechtigt sind.

    Ishildur schrieb:

    #pragma warning(disable:4100) // unreferenced formal parameter [unused method parameters]
    

    Viele Interfaces erwarten Parameter, welche jedoch von einigen konkreten Implementierungen nicht genutzt werden.

    Wenn ich Parameter nicht benutze, und dies mit Absicht geschieht, sieht das bei mir in der cpp-Datei so aus:

    void foo(
        int /* paramname */)
    {
    }
    

    Damit umgehe ich Einerseits die Warnung, und weise auch darauf hin, das ich den Parameter bewusst nicht nutze.

    Ishildur schrieb:

    #pragma warning(disable:4127) // conditional expression is constant [while(true)]
    

    Oft hat man keine Ahnung, wie oft eine schleife durchlaufen wird, sie wird mit einem break verlassen.

    Oft? Ich kenne dies als Sonderfall, mag bei dir anders sein. Aber ich will auch die Fälle sehen in denen Unabsichtlich ein konstanter Ausdruck entsteht (Ist mir auch schon einmal nach einer Codeanpassung passiert).

    usw.

    Ich sehe jedenfalls weiterhin keinen einzigen wirklichen Grund, Warnungen und Fehler als "unsinnig" anzusehen, da es durchaus mal Gründe für eben jene gibt. Lieber einmal ein umschließendes pragma warning push/pop als Warnungen zu übersehen, an Stellen, an denen sie ihre Bewandtnis haben.

    Ishildur schrieb:

    Also schreibe ich weniger intuitiven Code, nur damit keine MS Compiler spezifische Warnung erscheint?

    Mit welcher Version bitte? Also die enum-Warnung kenne ich z.B. garnicht, obwohl ich grundsätzlich mit höchster Warnstufe arbeite. Und merkwürdigerweise muss ich in der Regel nur selten eine Warnung absichtlich (und sehr lokal) unterdrücken um keine Warnung am Schluss zu erhalten; Und in der Regel unterdrücke ich fast ausschließlich nur Warnungen in Kombination mit externen Bibliotheken.

    Verwende ich den MS-Compiler nun falsch, weil ich keine Probleme mit Warnungen habe? 😉



  • Oft? Ich kenne dies als Sonderfall,

    Praktisch jeder iterativ implementierte Suchalgorithmus...


Anmelden zum Antworten