"Fehler: »nullptr« wurde in diesem Gültigkeitsbereich nicht definiert" Was mach ich falsch?



  • Hallo zusammen,

    ich bin absoluter Anfänger was c++ angeht.
    Seit nun 2 Tagen schlag ich mich mit dem unten aufgeführten Problem herum.
    Da c++ die erste Programmiersprache ist mit der ich mich ernsthaft auseinander setze, fällt mir die Fehlersuche online leider auch sehr schwer.

    Zu meinem "Problem".

    Wenn ich versuche das Programm (ein Übungsprogramm aus einem Lehrbuch)
    zu compilieren bekomme ich immer den folgenden Fehler:

    Fehler:>> nullptr wurde in diesem Gültigkeitsbereich nicht definiert.

    Ich verwende Anjuta, und bisher hat alles ganz gut funktioniert.
    Ich habe auch schon versucht nullptr gegen "0" zu tauschen. Da meckert der Compiler dann zwar nicht mehr, aber es kommt nach dem compilieren nur Schrott raus.

    Bin über jeden Tip der mich weiterbringt sehr dankbar. Wie gesagt ich beiß mir seit 2 Tagen schon die Zähne dran aus, ohne das ich Land sehe.

    Grüße Matt

    Hier das Programm:

    #include <iostream>
    using namespace std;
    
    struct WoW_t {
      string klasse;
      string nickname;
      unsigned int freund_seit;
      WoW_t *next;
    };
    
    int main()
    {
      int wahl;
      WoW_t *anfang = nullptr, *hilfsZeiger, *freund;
      do{
        cout << "-1- Freund hinzufuegen\n";
        cout << "-2- Freunde ausgeben\n";
        cout << "-3- Beenden\n";
        cout << "Deine Wahl: ";
        cin >> wahl;
        switch(wahl) 
        {
          case 1:
            freund = new WoW_t;
            cout << "Klasse : ";
            cin >> freund->klasse;
            cout << "Name : ";
            cin >> freund->nickname;
            cout << "Verbund : ";
            cin >> freund->freund_seit;
            if(anfang == nullptr)
            {
              anfang = freund;
              freund->next = nullptr;
            }
            else
            {
              hilfsZeiger = anfang;
              while(hilfsZeiger->next != nullptr)
              {
                hilfsZeiger = hilfsZeiger->next;
              }
              hilfsZeiger->next = freund;
              freund->next = nullptr;
            }
            break;
          case 2:
            cout << "Deine WoW-Freunde\n\n";
            hilfsZeiger = anfang;
            while(hilfsZeiger != nullptr) 
            {
              cout << "Klasse : " << hilfsZeiger->klasse;
              cout << "\nName : " << hilfsZeiger->nickname;
              cout << "\nVerbund: " << hilfsZeiger->freund_seit << endl;
              hilfsZeiger = hilfsZeiger->next;
            }
            break;
        }
      }while(wahl != 3);
      return 0;
    }
    [code="cpp"]
    


  • Dein Compiler versteht kein C++11 bzw. es fehlt ein entsprechender Compileschalter. 0 sollte aber auch funktionieren, du hast also vermutlich einen Fehler im Programm.



  • matthn80 schrieb:

    Fehler:>> nullptr wurde in diesem Gültigkeitsbereich nicht definiert.

    Ich verwende Anjuta, und bisher hat alles ganz gut funktioniert.

    Das Schlüsselwort nullptr ist ziemlich neu, es wurde erst im seit 2011 gültigen C++-Standard hinzugefügt. Entweder dein Compiler kann das noch nicht, oder du hast irgend eine Einstellung getätigt, die ihn im C++98-Modus laufen lässt oder dergleichen.

    Vor nullptr hat man einfach 0 geschrieben. Das ist nicht exakt äquivalent (z.B. bei der Funktionsüberladung), aber in deinem Fall macht es keinen Unterschied.

    Wenn du jetzt "Schrott" bekommst, solltest du das mal näher definieren. So auf den ersten Blick seh ich keinen Fehler (mal von der fehlenden Speicherfreigabe abgesehen.)



  • #if __cplusplus < 201103
        struct nullptr_t
        {
            template <typename T>
            operator T*() const { return 0; }
        } nullptr;
    #endif
    

    Wenn schon, dann bitte ordentlich...


  • Administrator

    Kellerautomat schrieb:

    #if __cplusplus < 201103
        struct nullptr_t
        {
            template <typename T>
            operator T*() const { return 0; }
        } nullptr;
    #endif
    

    Wenn schon, dann bitte ordentlich...

    *hust*

    #if __cplusplus < 201103
    
    const class { 
    public: 
         template<class T> operator T*() const  {return 0;} 
         template<class C, class T> operator T C::*() const  {return 0;} 
    private: 
         void operator&() const; 
    } nullptr = {};
    
    #endif // __cplusplus < 201103
    

    http://www.c-plusplus.net/forum/220511

    😉

    Grüssli



  • Wobei dadurch, dass das Objekt keinen Status hat, die Aggregat-Initialisierung und das const beinahe an Paranoia grenzen...



  • Übrigens, es wäre schöner

    class { 
    ...
    } const nullptr = {};
    

    Zu schreiben. Sonst verwirrt man Menschen durch "const class".



  • Und der Klassenname ist essentiell fuer Overloading.



  • Aber sowieso ist falsch was ihr da macht, seht mal her:

    N3337 [basic.fundamental]/10 schrieb:

    sizeof(std::nullptr_t) shall be equal to sizeof(void*).

    Aber für eure Implementierung ist natürlich die Größe eines Objektes 1.

    Aber alignas(void*) gibt es ja erst seit C++11 ... 🤡
    Daher schön einen Member zum padden.


  • Mod

    Sone schrieb:

    Aber sowieso ist falsch was ihr da macht, seht mal her:

    N3337 [basic.fundamental]/10 schrieb:

    sizeof(std::nullptr_t) shall be equal to sizeof(void*).

    Aber für eure Implementierung ist natürlich die Größe eines Objektes 1.

    Aber alignas(void*) gibt es ja erst seit C++11 ... 🤡
    Daher schön einen Member zum padden.

    Der Standard legt auch fest, dass nullptr_t ein fundamentaler Typ ist, damit kommt eine Implementierung als Klasse sowieso nicht in Frage.



  • camper schrieb:

    Sone schrieb:

    Aber sowieso ist falsch was ihr da macht, seht mal her:

    N3337 [basic.fundamental]/10 schrieb:

    sizeof(std::nullptr_t) shall be equal to sizeof(void*).

    Aber für eure Implementierung ist natürlich die Größe eines Objektes 1.

    Aber alignas(void*) gibt es ja erst seit C++11 ... 🤡
    Daher schön einen Member zum padden.

    Der Standard legt auch fest, dass nullptr_t ein fundamentaler Typ ist, damit kommt eine Implementierung als Klasse sowieso nicht in Frage.

    Schon klar:

    A value of type std::nullptr_t is a null pointer constant

    N3337 [conv.ptr]/1 schrieb:

    A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to
    zero or a prvalue of type std::nullptr_t.

    Aber trotzdem. Würde für real existierenden Code die Semantik eine andere sein, wenn nullptr_t eine Klasse ist die die entsprechenden Konvertierungsoperatoren definiert?



  • Anjuta = GCC = Der läuft auch in neueren Versionen standardmäßig im C++03 Modus.
    Lösung: -std=c++0x bzw -std=c++11



  • Hallo,

    vielen Dank für die schnelle Hilfe.
    Leider hab ich noch nicht genug Fachvokabular und Knowhow um alle Tips hier zu verstehen.

    Ich hab das Programm jetzt noch einmal mit 0 anstelle von nullptr geschrieben.
    Was mir dieses mal aufgefallen ist, wenn ich beim ausführen Buchstaben als variable eingebe dreht mein Programm durch. Heißt das es mir die Auswahl in einer endlosen Schleife wiedergibt. Verwende ich allerdings Zahlen funktioniert alles.

    @Ethon, kannst Du mir bitte genau sagen wo ich c++11 in Anjuta aktiviere?
    Wenn ich dich richtig verstehe ist das ein Befehl den ich im Programm als Header angebe? Hab es schon versucht, aber irgendwas mach ich falsch.

    Grüße
    Matt



  • Hast du schon mal selbst etwas mit dem GCC kompiliert? Meistens wird eine recht lange Befehlszeile übergeben wie zb

    g++ -o MeinProgramm -O2 -I./include test.cpp
    

    Was so viel bedeutet wie dass dem g++ gesagt wird, dass er die erstellte Datei als MeinProgramm speichern, Optimierungslevel 2 verwenden, den Ordner ./include zum Suchpfad hinzufügen soll, für das Kompilieren der Datei test.cpp.

    Das -std=c++0x gehört an irgendeinen Platz in der Befehlszeile bevor die Quelldatei aufgelistet wird.
    Ich habe nur leider keine Ahnung von Anjuta - kannst du da irgendwo deine eigenen Compilerflags übergeben?

    Ich sehe gerade, bei Anjuta kannst du die CXX_FLAGS setzen. Zu denen gehört dasd -std=c++0x .
    https://developer.gnome.org/anjuta-build-tutorial/3.2/figures/configure-dialog.png.en


  • Administrator

    matthn80 schrieb:

    Leider hab ich noch nicht genug Fachvokabular und Knowhow um alle Tips hier zu verstehen.

    Dann frag nach, was du nicht verstehst. Sind nämlich gute Tipps und durch das Nachfragen erweiterst du dein Wissen.

    matthn80 schrieb:

    Was mir dieses mal aufgefallen ist, wenn ich beim ausführen Buchstaben als variable eingebe dreht mein Programm durch. Heißt das es mir die Auswahl in einer endlosen Schleife wiedergibt. Verwende ich allerdings Zahlen funktioniert alles.

    Das Problem ist, dass beim ersten Einlesen du einen int einliest. Heisst es wird eine Zahl erwartet. Wenn keine Zahl kommt, geht der Stream ( std::cin ) in einen Fehlerzustand und solange er in diesem Fehlerzustand ist, wird jede Leseoperation auf der Stelle abgebrochen.

    Du musst solche Fehler abfangen und entsprechend verarbeiten. Dazu helfen dir Funktionen wie fail , good und clear . Du kannst aber nicht einfach nur den Fehlerzustand zurücksetzen, da die Eingabe, welche nicht verarbeitet werden konnte, noch im Stream drin ist. Diese Eingabe muss du somit zuerst verwerfen, was du wiederrum darüber machen kannst:

    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    

    Siehe auch: http://en.cppreference.com/w/cpp/io/basic_istream/ignore

    Am Ende bietet sich meistens allerdings an, dass du bei solchen Eingaben immer Zeilenweise einliest mit std::getline . Die Chance, dass getline fehlschlägt, ist äusserst klein und könnte man allenfalls in Zukunft ebenfalls einfach abfangen. Wenn du die Linie hast, kannst du sie danach in eine Zahl umwandeln und die Fehler abfangen, siehe dazu:
    http://www.c-plusplus.net/forum/39488

    matthn80 schrieb:

    Wenn ich dich richtig verstehe ist das ein Befehl den ich im Programm als Header angebe? Hab es schon versucht, aber irgendwas mach ich falsch.

    Nein, das sind Kompileroptionen (Kommandozeilen-Parameter). Ich kenne leider Anjuta nicht, aber das sollte man irgendwo unter den Einstellungen oder Projekt-Eigenschaften einstellen können.

    Grüssli



  • Dravere schrieb:

    Du musst solche Fehler abfangen und entsprechend verarbeiten. Dazu helfen dir Funktionen wie fail , good und clear .

    Hmm. Meistens erledigt man das über den Konvertierungsoperator. So ist das auch Gedacht.



  • Andere Tipps:

    • für std::string musst du auch irgendwo mal #include <string> geschrieben haben
    • In C++ musst du Variablen nicht alle am Anfang einer Funktion definieren. Du kannst sie "lokaler" definieren, was einserseits IMHO die Lesbarkeit erhöht und andererseits recht praktisch sein, wenn du einer Variable eine kürzere Lebenszeit gibst. Ich denke da speziell an hilfsZeiger und freund .
    • Datenstrukturen wie verkette Listen (und mehr) gibt es ja schon fertig in der Standardbibliothek. Man muss und sollte in der Hinsicht das Rad nicht neu erfinden.
    • Vermeide Funktionen die ganz viele Dinge auf einmal tun. Gliedere solche Sachen aus. Halte Funktionen klein und rufe ggf andere Funktionen darin auf, die entsprechende Namen haben, damit der Leser sich ein Bild davon machen kann, was darin passiert.
    #include <iostream> 
    #include <string>
    #include <vector>
    
    using namespace std; 
    
    struct WoW_t
    { 
      string klasse; 
      string nickname; 
      unsigned int freund_seit; 
    }; 
    
    void eingabe(WoW_t & freund)
    {
      cout << "Klasse  : "; cin >> freund.klasse;
      cout << "Name    : "; cin >> freund.nickname;
      cout << "Verbund : "; cin >> freund.freund_seit;
    }
    
    void anzeigen(vector<WoW_t> const& freunde)
    {
      cout << "\nDeine WoW-Freunde\n"; 
      for (auto& freund : freunde) {
        cout << "Klasse : " << freund.klasse;
        cout << "\nName   : " << freund.nickname;
        cout << "\nVerbund: " << freund.freund_seit << endl;
      }
    }
    
    int main() 
    {
      vector<WoW_t> freunde;
      int wahl;
      do { 
        cout << "-1- Freund hinzufuegen\n"; 
        cout << "-2- Freunde ausgeben\n"; 
        cout << "-3- Beenden\n"; 
        cout << "Deine Wahl: "; 
        wahl = 3;
        cin >> wahl;
        switch(wahl) { 
          case 1: {
            freunde.emplace_back();  // neues Element am Ende hinzufuegen
            eingabe(freunde.back()); // ...und befuellen
            break;
          }
          case 2: {
            anzeigen(freunde);
            break;
          }
        } 
      } while (wahl != 3); 
      return 0; 
    }
    

    So ist das ein bisschen besser. Allerdings ist hier noch keine ordentliche Fehlerbehandlung bzgl der Eingabe drin.


  • Administrator

    Sone schrieb:

    Dravere schrieb:

    Du musst solche Fehler abfangen und entsprechend verarbeiten. Dazu helfen dir Funktionen wie fail , good und clear .

    Hmm. Meistens erledigt man das über den Konvertierungsoperator. So ist das auch Gedacht.

    Ja, aber ehrlich gesagt ist meine Erfahrung damit inzwischen die folgende: Das verwirrt die meisten Anfänger nur. Eine Funktion welche good oder fail heisst, sagt den Leuten viel mehr, als irgendein seltsamer Konvertierungsoperator. Ehrlich gesagt empfinde ich es auch als eine recht seltsame Designentscheidung, wie so vieles bei den C++ Streams.

    Grüssli



  • Dravere schrieb:

    Ehrlich gesagt empfinde ich es auch als eine recht seltsame Designentscheidung, wie so vieles bei den C++ Streams.

    Schon, aber irgendwie ist das auch ein wenig literarisch, nicht?

    if( std::cin >> a )
    

    liest sich doch so schön. Schöner als

    if( !std::cin.operator>>(a).fail() )
    

    Eine Funktion welche good oder fail heisst, sagt den Leuten viel mehr, als irgendein seltsamer Konvertierungsoperator.

    Da hast du Recht. Aber wäre es nicht auch besser gewesen, std::vector std::dynamic_array zu nenne, und valarray stattdessen vector ?

    Außerdem verstehen Anfänger anfangs sowieso einiges nicht. Die Qualifizierung mit std oder das using namespace ist meistens nicht sofort erklärbar, wie einiges andere auch, sondern das muss man einfach so hinnehmen wie es ist und warten bis es dran kommt.



  • Sone schrieb:

    Dravere schrieb:

    Ehrlich gesagt empfinde ich es auch als eine recht seltsame Designentscheidung, wie so vieles bei den C++ Streams.

    Schon, aber irgendwie ist das auch ein wenig literarisch, nicht?

    if( std::cin >> a )
    

    liest sich doch so schön. Schöner als

    if( !std::cin.operator>>(a).fail() )
    

    So hat Dravere das sicher nicht gemeint.


Anmelden zum Antworten