Array in Ausdruch erzeugen



  • [quote Nexus]Wobei ich mich generell frage, was die Motivation dahinter ist, alles in eine Zeile zu packen. In so einem Falle sollte man aber auch Makros so exzessiv wie möglich nutzen... [/quote]
    Es gibt zwei Gruppen von Menschen:
    die erste Gruppe würde "strcpy" implementieren als:

    //...
    	size_t length = strlen(quelle);
    	for(size_t i=0; i<=length; i++) ziel[i] = quelle[i];
    //...
    

    und die zweite Gruppe als:

    //..
    	while(*ziel++ = *quelle++);
    //...
    

    Ein erfahrener C/C++-Programmierer würde wohl das zweite Beispiel vorziehen.
    Und wenn es ausreichend übersichtlich ist, dann packt man auch Einiges in eine Zeile.

    @asc:
    Na, das ist ja wunderbar. Dann halt:

    const unsigned SIZE = 5;
    foo( (int[SIZE]){1,2,3,4,5} );
    

    Und hättest du hier ein Problem gehabt, dann würdest du auch mit einem benamten Array dieses Problem haben.



  • user13 schrieb:

    @asc:
    Na, das ist ja wunderbar. Dann halt:

    const unsigned SIZE = 5;
    foo( (int[SIZE]){1,2,3,4,5} );
    

    Und hättest du hier ein Problem gehabt, dann würdest du auch mit einem benamten Array dieses Problem haben.

    Dann passen wir jetzt mal foo an, das es mit 6 Parametern arbeiten kann. Und ja, ich würde garnicht zum C-Array greifen. Die STL und TR1 bieten sicherere Alternativen. Sei es nun std::vector oder std::tr1::array.

    cu André



  • user13 schrieb:

    Ein erfahrener C/C++-Programmierer würde wohl das zweite Beispiel vorziehen.

    Und das aus gutem Grund. Der allerdings nicht darin besteht, dass die zweite Variante in eine Zeile passt. Das ist ein netter Nebeneffekt. Hauptgrund ist die höherere Performance. Wenn die Performance der ersten Variante höher wäre, dann wäre strcpy auch so implementiert, unabhängig davon ob's dafür mehr Zeilen braucht.



  • @ user13:
    Netter Trick mit dem strcpy() . Nur kommt man glaube ich selten auf die Idee, zuerst mit strlen() die Länge abzufragen, um dann nochmals alle Zeichen bis zum '\0' durchzuiterieren. Mich wundert es eigentlich, dass du nicht auf die Idee gekommen bist, strlen(quelle) gerade in den Schleifenkopf zu schreiben.

    Womit schon wieder eine Zeile wegfallen würde.

    Und was das Standardargument Performance betrifft: Woher weisst du, wie viel es ausmacht, wenn man zuerst ein Objekt erzeugt und dann dieses übergibt? Bzw. ob es überhaupt was ausmacht?

    Naja, hier finde ich "premature optimization is the root of all evil in programming" ganz passend... Es gibt leider einfach zu viele Leute, die für einige Nanosekunden die Sicherheit und Übersichtlichkeit des Codes aufs Spiel setzen. Schau doch nur mal die C++-Streams an, die sind nicht gerade performant. Es ist aber auch jedem überlassen, printf() und Co. zu verwenden...



  • Also gut. Ich will nicht von jedem in einen Disput verwickelt werden.

    Und was das Standardargument Performance betrifft: Woher weisst du, wie viel es ausmacht, wenn man zuerst ein Objekt erzeugt und dann dieses übergibt? Bzw. ob es überhaupt was ausmacht?

    Ich bin in keinem meiner Beiträge auf die Performance eingeganen, sondern auf die Prägnanz.

    Die Beispiele sollten nur klar machen, dass man statt "lang und übersichtlich" wohl eher "kurz und übersichtlich" nehmen würde. Ich wollte gar nicht auf die Performance eingehen, da würe ich eher etwas in Richtung Duff's device nehmen, wenn sie gefordert wird.
    Na dann halt so:

    entweder:
    //..
        while(*quelle != '\0'){
    	*ziel = *quelle;
    	*ziel++;
    	*quelle++;
    	}
        *ziel = '\0';
    //...
    
    oder:
    //..
        while(*quelle != '\0'){
    	*ziel++ = *quelle++;
    	}
        *ziel = '\0';
    //...
    
    oder:
    //..
        size_t i;
        for(i=0; quelle[i]!='\0'; i++) ziel[i] = quelle[i];
        quelle[i] = '\0';
    //..
    
    und nocht tausende weitere, wenn ihr wollt......
    
    oder letzten Endes:
    //..
        while(*ziel++ = *quelle++);
    //...
    

    Was jetzt? Irgendwelche Performance Unterschiede? Wohl eher nicht.
    Und? Was werdet ihr nehmen? Klar, einfach std::string, oder? Aber davon haben wir gar nicht gesprochen.

    Das Problem ist:
    Gibt es eine Möglichkeit folgenden Code zu verkürzen?

    int array[] = {1, 2, 3};
    myfunc(array);
    

    Ja.
    Mein Vorschlag war:

    myfunc( (int[3]){1, 2, 3} );
    

    1. Das Problem wurde behoben: der Code ist kürzer geworden.
    2. Ist der Code übersichtlich genug: ja, ja und noch mal ja.
    3. Hätte die Ausführung des zweiten Fragments irgendwelche Laufzeitnachteile oder -vorteile gegenüber dem ersten: nein, jedenfalls sehe ich keine. Ein Array wird erzeugt, übergeben und danach zerstört. Der Unterschied ist bloß, dass im ersten Fragment ein benamter, im zweiten ein unbenamter Array erzeugt wird.

    Das allgemeine Problem, dass man die Arraygröße bereits zur Compilerzeit wissen muss, um keine Fehler zu begehen, ist mir selbstverständlich bewußt. Dass in vielen Situationen Container die bessere Alternative zu Arrays sind, ist klar. Aber bei diesem Problem ist es nicht der Fall. Und eure kurze Sichtweise, dass man überall dort Container verwendet soll, wo es auch geht, ist falsch. C++ unterstützt viele Paradigmen. Bloß weil ihr euch nur auf eine stützt, macht aus euch keine besseren Programmierer.

    Ich weiß nicht, was ihr jetzt noch ausdenken werdet. Jedenfalls behaupte ich nicht, dass man überall, wo es nur geht, diese unbenamte Array verwendet soll. Sondern nur dort, wo sie auch angebracht sind. Bei diesem Problem ist es der Fall gewesen.
    Ich bin kein "eine Zeile"-Freak. Ich strukturiere meinen Code so übersichtlich wie es nur geht. Bei diesem Problem benutze ich einen unbenamten Array. Und ich glaube, viele würden das auch so machen. Schließlich gibt's noch Kommentare.
    Wie dem auch sei, mein Vorschlag ist besser als eure.

    Überzeugt mich, dass ich mich irre.



  • Hört! Hört! Das musste (wirklich) mal gesagt werden! 😃



  • user13 schrieb:

    Und eure kurze Sichtweise, dass man überall dort Container verwendet soll, wo es auch geht, ist falsch. C++ unterstützt viele Paradigmen. Bloß weil ihr euch nur auf eine stützt, macht aus euch keine besseren Programmierer.

    Ich halte mich tatsächlich aus einen Grund als besseren Programmierer:
    Ich versuche Code zu schreiben der auch die nächste Wartung überstehen kann, und nicht so leicht unnötige Fehlerquellen einbaut, die man erst schwer zur Laufzeit ausmachen kann. Ich habe Compilerfehler lieber als laufzeitfehler.

    // Getestet unter Visual C++ Express Edition, Servicepack 1
    #include <array>
    #include <iostream>
    
    void foo(std::tr1::array<int, 5> const & arr)
    {
        for(std::tr1::array<int, 5>::const_iterator it=arr.begin(), end=arr.end(); it!=end; ++it)
            std::cout << (*it) << std::endl;
    }
    
    int main()
    {
        std::tr1::array<int, 5> arr = {1,2,3,4,5};
        foo(arr);
    }
    

    Der Code ist nun etwas länger, aber wenigstens bekommt man einen Fehler, wenn man jetzt die Funktion anpasst und statt 5 nun z.B. 10 Werte benötigt.



  • user13 schrieb:

    ...
    Das allgemeine Problem, dass man die Arraygröße bereits zur Compilerzeit wissen muss, um keine Fehler zu begehen, ist mir selbstverständlich bewußt. Dass in vielen Situationen Container die bessere Alternative zu Arrays sind, ist klar. ...

    Und woher soll der geneigte Leser hier wissen, was Dir "selbstverständlich" und "klar" ist ?
    Du (bzw. jemand, der den jederzeit frei verfügbaren Nick "user13" genutzt hat) hast hier unkommentiert ein "unübliches" Stückchen Code in die Runde geworfen - als Antwort auf die Frage eines (vermeindlichen) Anfängers (zumindestens lässt die Syntaxfrage das vermuten).

    => Du hast am falschen Ende gespart (oder wolltest eigentlich nur eine Diskussion über Deine Kompetenz initiieren).

    Gruß,

    Simon2.



  • Simon2 schrieb:

    user13 schrieb:

    ...
    Das allgemeine Problem, dass man die Arraygröße bereits zur Compilerzeit wissen muss, um keine Fehler zu begehen, ist mir selbstverständlich bewußt. Dass in vielen Situationen Container die bessere Alternative zu Arrays sind, ist klar. ...

    Und woher soll der geneigte Leser hier wissen, was Dir "selbstverständlich" und "klar" ist ?
    Du (bzw. jemand, der den jederzeit frei verfügbaren Nick "user13" genutzt hat) hast hier unkommentiert ein "unübliches" Stückchen Code in die Runde geworfen - als Antwort auf die Frage eines (vermeindlichen) Anfängers (zumindestens lässt die Syntaxfrage das vermuten).

    => Du hast am falschen Ende gespart (oder wolltest eigentlich nur eine Diskussion über Deine Kompetenz initiieren).

    Gruß,

    Simon2.

    Weil ja jeder anfänger mit

    // Getestet unter Visual C++ Express Edition, Servicepack 1 
    #include <array> 
    #include <iostream> 
    
    void foo(std::tr1::array<int, 5> const & arr) 
    { 
        for(std::tr1::array<int, 5>::const_iterator it=arr.begin(), end=arr.end(); it!=end; ++it) 
            std::cout << (*it) << std::endl; 
    } 
    
    int main() 
    { 
        std::tr1::array<int, 5> arr = {1,2,3,4,5}; 
        foo(arr); 
    }
    

    direkt was anfangen kann...



  • ... sofern er sich ganz kurz mit der syntax der Container und ihrer Funktionen auseinandersetzt. ja ?
    Kann ich als Anfänger bestägigen 😃



  • muh schrieb:

    Weil ja jeder anfänger mit ...
    direkt was anfangen kann...

    Und deshalb soll man einen Anfänger also fehlerträchtigen Code vermitteln und C-Arrays verwenden, die ebenso komplex sind (Wenn man die vielen Fragen zur Zuweisung, Kopie, Übergabe etc. bedenkt kann niemand behaupten, das Arrays einfacher zu verstehen sind).

    Ja, ich hätte den Code "vereinfachen" können (using namespace; Indexzugriff; Call-By-Value). Aber ich halte auch Anfänger in der Lage, Fragen zu stellen, und zeige ihnen lieber wie der Code in einer Anwendung in etwa aussehen sollte. Ich habe etwas dagegen Code zu vermitteln der
    a) Unnötig fehlerträchtig ist...
    b) ... in sauberen Anwendungen daher eh nicht eingebaut werden sollte...
    c) ... und damit unnötiges Wissen darstellt.
    Lieber liefer ich eine weitere Erläuterung nach.

    Zum einen sehe ich dann, das der Anfänger auch wirklich Interesse hat (Nachfragen kostet nichts, außer vielleicht Zeit), und das er sich zumindestens mal mit den Code auseinander gesetzt hat (ohne fehlerträchtigen Code 1:1 in seinen Code per Copy/Paste zu übernehmen).

    cu André
    P.S: Ich will garnicht behaupten das ich von Anfang an sauberen Code gelernt habe, aber dennoch kenne ich es von mir das man alte Gewohnheiten schwerer ablegt. Wieso sollte ich also gleich Gewohnheiten schaffen von denen ich weiß, das er sie später ablegen muss?



  • Wie heißts so schön? "Mit gutem Beispiel vorangehen" - ein schlechtes Beispiel zu liefern nur weils leichter verständlich ist ist absolut der falsche Weg.
    Mal abgesehen davon dass die Einstellung "das ist fortgeschrittenes C++, das versteht der eh nicht" ganz schön arrogant ist und oft nicht der Wahrheit entspricht. Einige hier sonnen sich gerne in der Illusion, dass Neulinge in C++ auf jeden Fall unintelligenter und lernresistenter sind als sie selbst und überschätzen dabei zusätzlich ihren eigenen Wissensstand.



  • Wenn man Arrays immer per Reference übergeben würde, hätte mein viele Probleme weniger.



  • KasF schrieb:

    Wenn man Arrays immer per Reference übergeben würde, hätte mein viele Probleme weniger.

    Vor allem, weil man dann die Größe immer zur Compilezeit festlegen müsste 🙄

    Felix



  • Phoemuex schrieb:

    Vor allem, weil man dann die Größe immer zur Compilezeit festlegen müsste

    Compiletime ist doch immer schön.

    Wenn alle Lib-Entwickler ihre "Array-Funktionen" so definieren würden, hätte wir ne Menge weniger Ärger:

    template<int S>
    void printArray( int (&array)[S] )
    {
        for(int i = 0; i < S; ++i) cout << array[i] << endl;
    }
    

    Ohne die Referenz würde das gar nicht funktionieren.

    Oder das ganze für alle Typen:

    template<typename T ,int S>
    void printArray( T (&array)[S] )
    {
        for(int i = 0; i < S; ++i) cout << array[i] << endl;
    }
    

    Edit: Gibt es dieses Idiom schon, wenn nicht ist es nun das KasF-Idiom 😉



  • muh schrieb:

    ...
    Weil ja jeder anfänger mit
    ...
    direkt was anfangen kann...

    Habe ich das behauptet ?
    Lies nochmal mein Post, dann wird Dir vielleicht klar, woran er meiner Ansicht nach gespart hat: An einer vernünftigen Erläuterung.

    Ich habe gar nicht seinen Code oder seine Lösung kritisiert, sondern die Art, wie er ihn präsentiert hat: Da hat er erstmal einen auf "coole Sau, die's nicht nötig hat, irgendetwas zu erklären" gemacht ... und sich hinter beschwert, dass ihn alle so furchtbar falsch einschätzen.
    2 kurze Sätze, WARUM er diese Lösung vorschlägt, hätten
    - dem OP geholfen, diesen Code in seinen Möglichkeiten und Grenzen zu beurteilen (und ggf. zu verstehen) und
    - dem Rest des Forums klarer gemacht, ob dieser Code aus gründlicher Erwägung entstanden ist oder nur Ergebnis eines längeren Rumgefummels bis zum Punkt "irgendwie tut's das jetzt" (denn solcher Code wird hier gar nicht so selten präsentiert und bei Unregs kann man das einfach nicht wissen).

    Das musste user13 dann alles mühsam (und in eine aufgeheizte Situation hinein) nachschieben ... was definitv mehr Aufwand war, als wenn er es gleich dazugeschrieben hätte.
    ERGO: Am falschen Ende gespart.

    Gruß,

    Simon2.


Anmelden zum Antworten