Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);"



  • Hallo mal eine Frage...

    Warum funktioniert das überhaupt ? 🙂

    int main(int argc, char** argv)
    {
       std::vector<std::string> myAllArgs(argv, argv + argc);
       for (auto argument : myAllArgs)
       {
          cout << argument << endl;
       }
    }
    

    Ich beziehe mich da auf diese Zeile:

    std::vector<std::string> myAllArgs(argv, argv + argc);
    

    Was mache ich da ? Und was müsste ich in meiner eigenen Klasse implementieren damit ich das auch dort machen kann ?

    Grüße



  • @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Was mache ich da ?

    Den vector mit Iteratoren initialisieren.
    Müsste es nicht eigentlich heißen: was habe ich da kopiert?

    Und was müsste ich in meiner eigenen Klasse implementieren damit ich das auch dort machen kann ?

    Einen Konstruktor implmentieren, der Iteratoren verwendet.
    Für den vector ist das:

    template< class InputIt >
    
    vector( InputIt first, InputIt last,
            const Allocator& alloc = Allocator() );
    

  • Mod

    Das ruft Variante 4 des Vector-Konstruktors auf:
    https://en.cppreference.com/w/cpp/container/vector/vector
    Es initialisiert den Vector also mit den Werten argv bis argv + argc oder in Arrayschreibweise gesagt mit argv[0] (inklusive) bis argv[argc] (exklusive). Da argv auf ein Feld der Länge argc zeigt (per Konvention zum Aufruf der main), sind das genau alle Einträge von argv. Also alle Argumente mit denen das Programm aufgerufen wurde plus dem Programmaufruf selbst (wieder per Konvention zum Aufruf der main). Da diese Argumente per Konvention als Zeiger auf nullterminierte char-Arrays übergeben werden kann man damit auch std::strings initialisieren, was der Konstruktor stillschweigend für einen erledigt.

    Oder weniger technisch ausgedrückt: Die Zeile transformiert die von C kommende Aufrufkonvention der main mit seinen Zeigern und nullterminierten Strings in etwas, das ein C++-Programmierer wiedererkennen kann.

    @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Und was müsste ich in meiner eigenen Klasse implementieren damit ich das auch dort machen kann ?

    Häh? Was? Wozu? Welche Klasse? Wovon redest du? Womit hast du Schwierigkeiten? Wenn du Fragen stellst, dann denk daran, dass wir weder deinen Code kennen, noch in deinen Kopf gucken können.



  • Du initialisierst den Vektor aus einem Iteratorpärchen, bzw. Zeigern auf Zeichenketten. Wenn argc 3 ist sieht das in etwa so aus:

    argv[0] = Pointer1; // normalerweise der Dateiname der Anwendung selbst
    argv[1] = Pointer2; // Param 1
    argv[2] = Pointer3; // Param 2
    

    Bei der Konstruktion eines Containers aus einem Iteratorpaar (wobei die char* Pointer hier als Iterator ausgewertet werden können) zeigt der erste Parameter auf das erste gültige Element und der zweite Parameter hinter das letzte gültige Element. Der Vektor initialisiert seinen Inhalt also mit Pointer1, Pointer2 und Pointer3.



  • @SeppJ sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Häh? Was? Wozu? Welche Klasse? Wovon redest du? Womit hast du Schwierigkeiten? Wenn du Fragen stellst, dann denk daran, dass wir weder deinen Code kennen, noch in deinen Kopf gucken können.

    Hallo

    Es gibt noch keine Code weder im Kopf noch sonstwo, das ist ja meine Frage. 🙂

    Also anderes gefragt:

    class MyClass
    { 
    }
    
    int main(int argc, char** argv)
    {
       std::vector<std::string> myAllArgs(argv, argv + argc);
       for (auto argument : myAllArgs)
       {
          cout << argument << endl;
       }
        // ???????????????????????????????????? 
        std::vector<MyClass> myAllIrgendwas(argv, argv + argc); // wird nicht funktionieren.
    }
    

    Das wird nicht funktionieren. Also die Frage: Was muss ich tun damit ich das auch bei MyClass anwenden kann. Abgesehen davon das die "Typen" nicht zusammenpassen.

    Aber ich denke manni66 hat mir den wichtigen Hinweis schon gegeben und ich kann erstmal weiter probieren. Danke erstmal.

    Grüße



  • @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Aber ich denke manni66 hat mir den wichtigen Hinweis schon gegeben

    Ja? Ich hatte angenommen, du woltest selber etwas in der Art von vector implementieren.

    Für std::vector<MyClass> muss deine Klasse einen Konstuktor mit char*, std::string oder auch std::string_view haben.



  • @manni66 sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Ja? Ich hatte angenommen, du woltest selber etwas in der Art von vector implementieren.

    Irgendwie schon weil ich zumindest jetzt weiß wonach ich jetzt suchen muss. Und der nächste Schritt wäre auch gewesen dass ich die Art von vector implmentieren will. Sonst habe ich immer Probleme das zu verstehen.

    also:

       MyVector<MyClass>  std::vector<MyClass> myElements(elements, elements + 10);
    

    Für ersten Fall brauche ich aber keinen Konstruktor mit string. Das geht auch einfach so.

    class MyClass
    {
    public:
       MyClass()
       {
       }
       string sinnlos;
    };
    
    int main(int argc, char** argv)
    {
       MyClass elements[10];
       elements[0].sinnlos  = "0";
       elements[1].sinnlos  = "1"; 
       elements[2].sinnlos  = "2";
       elements[3].sinnlos  = "3";
       elements[4].sinnlos  = "4";
       elements[5].sinnlos  = "5";
       elements[6].sinnlos  = "6";
       elements[7].sinnlos  = "7";
       elements[8].sinnlos  = "8";
       elements[9].sinnlos  = "9";
    
       std::vector<MyClass> myElements(elements, elements + 10);
       for (auto argument : myElements)
       {
          cout << argument.sinnlos << endl;
        }
    }
    

    hmmmmmmmm dieses/er "Syntax" geht mir schon etwas zu schnell 🙂

    Aber damit wird es zumindestens klarer.

    vector( InputIt first, InputIt last,
            const Allocator& alloc = Allocator() );
    


  • Der Sinn deiner Knödelei lässt sich nicht erkennen. Der gleiche Effekt in kurz:

    #include <iostream>
    #include <string>
    #include <iterator>
    
    using namespace std;
    
    class MyClass
    {
    public:
       string sinnlos;
    };
    
    int main(int argc, char** argv)
    {
       MyClass elements[] = {"0", "1", "2", "3" };
    
       for (auto& argument : elements)
       {
          cout << argument.sinnlos << endl;
        }
    }
    


  • @manni66 sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Der Sinn deiner Knödelei lässt sich nicht erkennen. Der gleiche Effekt in kurz:

    ÄÄ ja natürlich geht das auch kürzer. 🙂

    Es geht nur um diese Zeile die mir tausend Fragen aufwirft:

       std::vector<MyClass> myElements(elements, elements + 10);
    

    Alles anderes ist das drumherum. Der Sinn ist, versuchen zu verstehen was die Zeile genau macht und warum das überhaupt compilierbar ist. Und der Compiler nicht sagt. "Syntax Error myElements is not defined" oder sowas.



  • @manni66 sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    MyClass elements[] = {"0", "1", "2", "3" };

    momentmal das ist doch gar nicht kompilierbar das geht doch nur wenn ich MyClass (std::initializer_list<int> list) implementiert habe ... 🤔



  • @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    MyClass elements[] = {"0", "1", "2", "3" };

    momentmal das ist doch gar nicht kompilierbar das geht doch nur wenn ich MyClass (std::initializer_list<int> list) implementiert habe ...

    Hast du das [] nach elements gesehen?



  • @hustbaer sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    MyClass elements[] = {"0", "1", "2", "3" };

    momentmal das ist doch gar nicht kompilierbar das geht doch nur wenn ich MyClass (std::initializer_list<int> list) implementiert habe ...

    Hast du das [] nach elements gesehen?

    Ja und mein compiler mag das nicht: "error: conversion from 'const char [2]' to non-scalar type 'MyClass' requested"

    class MyClass
    {
    public:
       MyClass()
       {
       }
       sinnlos = myString;
    };
    
    int main(int argc, char** argv)
    {
       MyClass elements[] = {"0", "1", "2", "3" };
       return 0;
    }
    

    Das feature funktioniert doch auch nur wenn die Klasse das implementiert hat. 🤔



  • @martin_zi Und wo sagt dir dein Kompiler, dass er hier den std::initializer mag? Er mag einen Konstructor der mit const char[2] irgendwie umgehen kann, z.B. ein Konstruktor, der einen std::string erwartet.



  • @Jockelx sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    @martin_zi Und wo sagt dir dein Kompiler, dass er hier den std::initializer mag? Er mag einen Konstructor der mit const char[2] irgendwie umgehen kann, z.B. ein Konstruktor, der einen std::string erwartet.

    Weil mir die Fehlermeldung irgendwie derzeit zu unverständlich ist interpretiere ich einfach irgendwas hinein. Aber du hast recht ich habe da was gemixt. Wenn ich dieses std::initializer_list<int> list habe kanne ich das machen:

          MyClass elements3 = {"0", "1", "2", "3" };
    //und nicht das:
          MyClass elements2[] = {"0", "1", "2", "3" };
    

    Der Hinweis mit der [] war mir aber zu wenig und habe ich erst jetzt verstanden was du meinst.

    Allerdings muss ich meine Klasse so bauen:

    class MyClass
    {
    public:
    	MyClass()
    	{
    	}
    	MyClass(const char *mychar)
    	{
    	}
    }
    

    Sollte das auch funktionieren ?

    class MyClass
    {
    public:
    	MyClass()
    	{
    	}
    	MyClass(std::string mychar)
    	{
    	}
    }
    

    Mit std::string gibt es immer noch dieselbe Fehlermeldung.



  • @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Ja und mein compiler mag das nicht: "error: conversion from 'const char [2]' to non-scalar type 'MyClass' requested"

    Du kannst die Elemente einzeln initialisieren:

    MyClass elements[] = {{"0"}, {"1"}, {"2"}, {"3"}};
    


  • Vielleicht etwas Code zum Verständnis wieso, weshalb, warum:

    #include <vector>
    #include <iostream>
    
    struct A
    {
        A(int i) {}
        A(int i, int j) {}
    };
    int main()
    {
      std::vector<A> a = {{1,2}, 3};
      std::cout << a.size();
    }
    
    


  • @martin_zi
    C++ hat die Regel dass immer nur eine "user defined conversion" implizit angewendet wird. D.h. wenn du etwas hast was ein Foo braucht, und Foo ist mit einem std::string erzeugbar, und der std::string ist mit einem const char* erzeugbar, dann kannst du da nicht einfach "blah" hinschreiben.
    Weil dazu zwei "user defined conversions" nötig wären:
    1x "eingebaute conversion" const char[5] -> const char*
    1x "user defined" const char* -> std::string
    1x "user defined" std::string -> Foo

    Also Beispiel

    void takeFoo(Foo f);
    void test() {
        takeFoo("blah"); // geht nicht weil zwei "user defined conversions" nötig
        takeFoo(std::string{"blah"}); // geht weil nur eine "user defined conversion" nötig
        takeFoo({"blah"}); // geht auch weil nur eine "user defined conversion" nötig
                           // {"blah"} wird hier als Initialisierung des std::string interpretiert
                           // und danach kommt 1x implizite konvertierung von std::string nach Foo
    }
    

    Zum Initialisieren eines Arrays brauchst du erstmal die {}. Bei einem MyClass Array müssen die Werte innerhalb der {} also geeignet sein MyClass Objekte zu initialisieren. D.h. {"a", "b"} ist vergleichbar mit takeFoo("blah") im Beispiel oben, geht also nicht.

    Bei {{"a"}, {"b"}} dagegen werden {"a"} und {"b"} als Initialisierung eines std::string verstanden, und dann kann mit nur einer "user defined conversion" ein MyClass Objekt gebastelt werden.



  • @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Ja und mein compiler mag das nicht: "error: conversion from 'const char [2]' to non-scalar type 'MyClass' requested"

    Es hat schon seinen Grund, dass in meinem vollständigen Beispiel die Klasse keinen Konstruktor hat.



  • @manni66 Das ist aber wieder ein Spezialfall (alles public Member, keine special member functions etc.). Und mMn. nix was man besonders pushen sollte.



  • @manni66 sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    @martin_zi sagte in Was mache ich hier ? "std::vector<std::string> myAllArgs(argv, argv + argc);":

    Ja und mein compiler mag das nicht: "error: conversion from 'const char [2]' to non-scalar type 'MyClass' requested"

    Es hat schon seinen Grund, dass in meinem vollständigen Beispiel die Klasse keinen Konstruktor hat.

    Äääämmm ahhhhh ja aber genau bei solchen Sachen habe ich ein Verständnis Problem.
    Ich erzähle mal so wie ich es verstehe und dann kann man mich korrigieren:

    Laut Buch und was ich sonst so finde gilt: "Falls kein Konstruktor angegeben wird, wird einer vom System automatisch erzeugt (implizite Konstruktordeklaration)."
    Damit hat eine Klasse auch wenn nicht angegebn einen Konstruktor.

    Will ich wirklich keinen haben muss ich mit delete arbeiten. Also:

    class MyClass
    { 
        MyClass() = delete;   
    };
    

    Weiter steht:
    Dieser vordefinierte Konstruktor (englisch default constructor) kann auch selbst
    geschrieben werden. Der Standard-konstruktor hat keine Parameter. Für eine Klasse X wird er einfach mit X(); deklariert.

    Für mich bedeutet das:

    class MyClass
    {
    public:
       MyClass()
       {
       }
       sinnlos = myString;
    };
    
    class MyClass
    {
    public:
       sinnlos = myString;
    };
    

    Das dass das Gleiche ist. Aber das ist wohl nicht so. Also woher weiß ich was der Compiler wirklich generiert ? Da ist ja dann wohl was da, was ich gar nie geschrieben wurde. Und schreibe ich zuviel ist auf einmal doch was weg 😃


Log in to reply