Seltsame Fehlermeldung



  • Hallo Leute,

    Ich habe mir eine kleine Feld-Klasse Programmiert.
    Die Funktioniert eigentlich auch wirklich sehr gut.
    Aber irgendwie bekomme ich eine seltsame Fehlermeldung

    4:33: Warnung: __VA_ARGS__ kann nur in Erweiterung eines variadischen C99-Makros auftreten [standardmäßig aktiviert]

    Hier ist der dazugehörige Quelltext:

    #define neu (X, ...)      new X(__VA_ARGS__)
    #define neuF(X, GROESSE)  new X[GROESSE]
    
    #define loesche (X)   delete X
    #define loescheF(X)   delete [] X
    
    #define DEKLARIERE_TURBO_FELD(NAME, GROESSE, TYP)  \
    class NAME {    \
    public: \
      NAME(); \
      virtual ~NAME();  \
      NAME(const NAME&) = default;  \
      NAME(NAME&&)  = default;  \
      NAME& operator=(const NAME&) = default;  \
      NAME& operator=(NAME&&) = default;  \
      virtual const TYP& operator[](int x) const; \
      virtual       TYP& operator[](int x);       \
      virtual const int groesse() const;          \
    private:  \
      TYP   *m_feld;  \
    };
    
    #define DEFINIERE_TURBO_FELD(NAME, GROESSE, TYP) \
    NAME::NAME()  \
    { \
      m_feld = neuF(TYP, GROESSE);  \
    } \
    NAME::~NAME() \
    { \
      loescheF(m_feld); \
    } \
    const TYP& NAME::operator[](int x) const  \
    { \
      return m_feld[x]; \
    } \
    TYP&  NAME::operator[](int x) \
    { \
      return m_feld[x]; \
    } \
    const int NAME::groesse() const \
    { \
      return GROESSE; \
    } \
    
    DEKLARIERE_TURBO_FELD(FeldAusInt, 12, int)
    DEFINIERE_TURBO_FELD(FeldAusInt, 12, int)
    
    int main()
    {
      FeldAusInt f;
    
      f[0] = 1;
      f[1] = 4;
    
      for(int i = 0; i < f.groesse(); ++i)
        ausgabe(f[i], "\n");
    }
    

    Kann mir Jemand sagen, warum die Fehlermeldung auftritt?

    MfG,

    Strontium


  • Mod

    #define neu (X, ...)      new X(__VA_ARGS__)
               ^ ein Leerzeichen zuviel
    


  • 3...2...1...



  • Danke

    Jetzt läuft es.



  • this is bad code 😡



  • bad code detector schrieb:

    this is bad code 😡

    Warum?

    Er funktioniert doch.



  • Nein, tut er nicht. Zieh mal eine Kopie eines solchen Feldes und dann sieh zu, wie dein Code explodiert, wenn er die selben Daten zweimal freigeben will. Davon abgesehen ist das Makrokonstrukt haarsträubend -- wenn man so etwas wirklich von Hand machen will, gibt es Templates.

    Aber mit einiger Wahrscheinlichkeit ist die sinnvolle Variante eh

    #include <array>
    
    typedef std::array<int, 12> FeldAusInt;
    

    Es scheint mir keinen Grund zu geben, für ein Feld kleiner, bekannter Größe zum Heap zu laufen. Ggf. gibt es std::vector.



  • Hallo,

    seldon schrieb:

    Nein, tut er nicht. Zieh mal eine Kopie eines solchen Feldes und dann sieh zu, wie dein Code explodiert, wenn er die selben Daten zweimal freigeben will.

    Ist mir auch gerade aufgefallen. Kann man aber noch nachbessern.

    Davon abgesehen ist das Makrokonstrukt haarsträubend -- wenn man so etwas wirklich von Hand machen will, gibt es Templates.

    Aber Templates mache doch das Programm dick.
    Außerdem gefällt mir das Blau in meinem Editor.

    Aber mit einiger Wahrscheinlichkeit ist die sinnvolle Variante eh

    #include <array>
    
    typedef std::array<int, 12> FeldAusInt;
    

    Nein, denn std::array ist nicht vererbar, und speichert seine Daten im Kellerspeicher.

    Es scheint mir keinen Grund zu geben, für ein Feld kleiner, bekannter Größe zum Heap zu laufen. Ggf. gibt es std::vector.

    Dafür wird mir aber der Kellerspeicher schneller Voll laufen.

    MfG,

    Strontium



  • Strontium schrieb:

    Es scheint mir keinen Grund zu geben, für ein Feld kleiner, bekannter Größe zum Heap zu laufen. Ggf. gibt es std::vector.

    Dafür wird mir aber der Kellerspeicher schneller Voll laufen.

    Und dein Code wird dadurch besser und schneller, weil du nicht auf dem Stack arbeitest?
    Und versuch Makros mal zu debuggen. Ich find sowas nie so toll...

    Und dein Code wird durch dieses Marko auch vergrössert, templates geben dir zusätzlich aber noch den Compiler als guten Fehlerleser, bei Markos guckt der nur, ob die Syntax stimmt mehr nicht.



  • Strontium schrieb:

    Davon abgesehen ist das Makrokonstrukt haarsträubend -- wenn man so etwas wirklich von Hand machen will, gibt es Templates.

    Aber Templates mache doch das Programm dick.
    Außerdem gefällt mir das Blau in meinem Editor.

    Templates erhöhen höchstens die Compilezeit.

    Aber mit einiger Wahrscheinlichkeit ist die sinnvolle Variante eh

    #include <array>
    
    typedef std::array<int, 12> FeldAusInt;
    

    Nein, denn std::array ist nicht vererbar, und speichert seine Daten im Kellerspeicher.

    Man sollte auch NIE von Containern erben, schon allein von Design her.
    [/quote]

    Es scheint mir keinen Grund zu geben, für ein Feld kleiner, bekannter Größe zum Heap zu laufen. Ggf. gibt es std::vector.

    Dafür wird mir aber der Kellerspeicher schneller Voll laufen.
    [/quote]
    Dann nimm std::vector oder unique_ptr. Und bei 12 ints ist das nicht relevant.



  • Man sollte auch NIE von Containern erben, [...]

    Ist Vererbung nicht eine der Grundprinzipien von OOP?
    Macht man bei anderen Sprachen (Ruby, Smalltalk) doch auch auch so.

    Und versuch Makros mal zu debuggen. Ich find sowas nie so toll...

    Durch den Schalter -E kann ich mir die Pre-Prozessoraussgaben ansehen lasst.
    Um zu sehen, wohin das Template expandiert muss ich mir schon die Maschinensprache lesen.



  • Strontium schrieb:

    Man sollte auch NIE von Containern erben, [...]

    Ist Vererbung nicht eine der Grundprinzipien von OOP?
    Macht man bei anderen Sprachen (Ruby, Smalltalk) doch auch auch so.

    Ja, aber in C++ verwendet man eben nicht nur OOP.
    Das ist der Vorteil von C++ gegenüber reinen OOP-Sprachen.
    Komposition ist auch mächtig, geschweige denn freie Funktionen.
    Erweiterung von Containern geht via Iteratoren und 'ner freien Funktion (siehe Header algorithm).

    Edit: Und was Makros angeht: Schon mal was von Typsicherheit gehört? Nee? Makros nämlich auch nicht.



  • Ja, aber in C++ verwendet man eben nicht nur OOP.

    Und heißt, ich darf nur dann OOP Programmieren, wenn es nicht mehr anders geht?
    Vielleicht haben wir nur anderen Vorstellungen von Programmdesign.
    Ich finde OOP eben eine geniale Sache um die Wartbarkeit und Erweiterbarkeit zu erhalten.

    Komposition ist auch mächtig, geschweige denn freie Funktionen.

    Aber auch Vererbung hat ihren Zweck.

    Und was Makros angeht: Schon mal was von Typsicherheit gehört? Nee? Makros nämlich auch nicht.

    1. Doch!
    2. Typsicherheit wird überbewertet
    3. Nenne mir bitte mal ein (Praxisrelevantes) Szenario wo bei meiner Lösung, die Typsicherheit verletzt wird.


  • IMHO ein Troll



  • Strontium schrieb:

    Ja, aber in C++ verwendet man eben nicht nur OOP.

    Und heißt, ich darf nur dann OOP Programmieren, wenn es nicht mehr anders geht?
    Vielleicht haben wir nur anderen Vorstellungen von Programmdesign.
    Ich finde OOP eben eine geniale Sache um die Wartbarkeit und Erweiterbarkeit zu erhalten.

    Komposition ist auch mächtig, geschweige denn freie Funktionen.

    Aber auch Vererbung hat ihren Zweck.

    Richtig, aber vererbung hat gravierende Nachteile gegenüber von Komposition, wie z.B. die statische Beziehung. Zur Laufzeit kannst du etwas Komponiertes austauschen, was Vererbtes nicht.
    Und es ging explizit um die Ableitung von Containern. Das ist rein vom Design her schon Schwachsinn (das verstehe ich in Java auch nicht, da wird so oft von Containern abgeleitet und alles, mir wird regelmässig schlecht dadurch).
    Vererbung und Komposition, beides gibt es, beides hat seine Anwendungsfälle und beides wird gebraucht/genutzt.

    Strontium schrieb:

    Und was Makros angeht: Schon mal was von Typsicherheit gehört? Nee? Makros nämlich auch nicht.

    1. Doch!

    Sehr gut.

    Strontium schrieb:

    1. Typsicherheit wird überbewertet

    Nein. In C++ nicht. Während andere Sprachen zwar die Typen überprüfen, oder da per Compiler was simulieren (Java-generics z.B.) ist das allein das Typsystem von C++ schon Turing-vollständig, sprich du kannst schon alles damit berechnen, was berechenbar ist, und das NUR allein mit dem Typsystem, nicht noch mit der Sprache (klar, da geht das auch).
    Des Weiteren gibt es Konzepte wie Const-Correctness, diese Konzepte zeigen dir während der Compiletime semantische Fehler, sprich verhidnern Bugs. Aber auch nur wenn man sie benutzt und anwendet und das machst du hier nicht.

    Strontium schrieb:

    1. Nenne mir bitte mal ein (Praxisrelevantes) Szenario wo bei meiner Lösung, die Typsicherheit verletzt wird.

    Da wird sicherlich jemand einen Fehler finden.



  • Nein. In C++ nicht. Während andere Sprachen zwar die Typen überprüfen, oder da per Compiler was simulieren (Java-generics z.B.) ist das allein das Typsystem von C++ schon Turing-vollständig, sprich du kannst schon alles damit berechnen, was berechenbar ist, und das NUR allein mit dem Typsystem, nicht noch mit der Sprache (klar, da geht das auch).

    Mir ist TMP sehr wohl bekannt, aber nur weil ich etwas kann sehe ich noch keinen Grund darin es auch möglichst weit auszureizen.
    TMP hat genauso Nachteile:
    * Langsamer Übersetzungsvorgang
    * Schwer lesbar.

    Des Weiteren gibt es Konzepte wie Const-Correctness, diese Konzepte zeigen dir während der Compiletime semantische Fehler, sprich verhidnern Bugs. Aber auch nur wenn man sie benutzt und anwendet und das machst du hier nicht.

    Meine Lösung unterstützt "Const-Correctness". Bitte aufzeigen, wo was fehlt.



  • Strontium schrieb:

    Ja, aber in C++ verwendet man eben nicht nur OOP.

    Und heißt, ich darf nur dann OOP Programmieren, wenn es nicht mehr anders geht?
    Vielleicht haben wir nur anderen Vorstellungen von Programmdesign.
    Ich finde OOP eben eine geniale Sache um die Wartbarkeit und Erweiterbarkeit zu erhalten.

    Leute gibts.

    Komposition ist auch mächtig, geschweige denn freie Funktionen.

    Aber auch Vererbung hat ihren Zweck.

    Klar, aber nicht bei Containern!

    Und was Makros angeht: Schon mal was von Typsicherheit gehört? Nee? Makros nämlich auch nicht.

    1. Doch!

    Reference Collapsing...

    1. Typsicherheit wird überbewertet

    Wenn dir Typsicherheit nicht wichtig ist, programmiere doch in JavaScript.
    Typsicherheit ist imo einer der größten Vorteile wenn C++.

    1. Nenne mir bitte mal ein (Praxisrelevantes) Szenario wo bei meiner Lösung, die Typsicherheit verletzt wird.

    Member int*:

    prog.cpp: In member function ‘virtual const int*& FeldAusInt::operator[](int) const’:
    prog.cpp:48:1: error: invalid initialization of reference of type ‘const int*&’ from expression of type ‘int*’
    


  • Leute gibts.

    Unglaublich 🙄

    Klar, aber nicht bei Containern!

    Sagt wer?

    Reference Collapsing...

    Gibts erst seit C++11. Wie ist man bloß die ganze Zeit ohne damit Ausgekommen.

    Wenn dir Typsicherheit nicht wichtig ist, programmiere doch in JavaScript.

    Typsicherheit wird überbewertet vs Typsicherheit ist sinnlos.
    Man kann auch zwischen den Extremen leben.



  • Strontium schrieb:

    Leute gibts.

    Unglaublich 🙄

    Ja, find ich auch. 😉

    Klar, aber nicht bei Containern!

    Sagt wer?

    Ich. Siehste doch. :p
    Um einen Container zu erweitern, kann man in C++ auch eine freie Funktion nutzen.
    Das ist schneller, besser etc.
    Es ist einfach mehr C++-like und man sollte sich in der Programmierung schon der Sprache anpassen.

    Reference Collapsing...

    Gibts erst seit C++11. Wie ist man bloß die ganze Zeit ohne damit Ausgekommen.

    Es gab nicht viel zum Collapsen.
    Aus T und & wurde T&.
    Aus T& und & wurde T& (bei Templates).
    T&& gabs ja noch nicht.

    Wenn dir Typsicherheit nicht wichtig ist, programmiere doch in JavaScript.

    Typsicherheit wird überbewertet vs Typsicherheit ist sinnlos.
    Man kann auch zwischen den Extremen leben.

    Nein. 😉



  • Man kann auch mit 'nem Hammer 'ne Schraube in die Wand hauen...


Log in to reply