C++ Best Practice für Schleife mit Abbruch in der Mitte

Gast #6173761
Hallo,

im folgenden Code habe ich in f() und g() jeweils eine Variante einer 
Schleife mit Abbruchbedingung in der Mitte. Mit getc() lies sich dies 
vermeiden, mit getline() sehe ich mich dazu gezwungen. Das Beispiel 
liest Zeilen aus einem Stream bis eine Leerzeile kommt.
1
#include <iostream>
2
#include <sstream>
3
#include <string>
4
#include <vector>
5
using namespace std;
6
vector <string> f (istream& is) {
7
        string s;
8
        vector <string> v;
9
        while (1) {
10
                getline (is, s);
11
                if ("" == s) {
12
                        break;
13
                }
14
                v.push_back (s);
15
        }
16
        return v;
17
}
18
vector <string> g (istream& is) {
19
        vector <string> v;
20
        for (string s;
21
                        getline (is, s),
22
                        "" != s;
23
            ) {
24
                v.push_back (s);
25
        }
26
        return v;
27
}
28
int main (int argc, char** argv) {
29
        string s = "Line 1\nLine 2\nLine 3\n\nLine 5";
30
        istringstream iss1 (s);
31
        for (auto a: f (iss1)) {
32
                cout << a << endl;
33
        }
34
        cout << "---" << endl;
35
        istringstream iss2 (s);
36
        for (auto a: g (iss2)) {
37
                cout << a << endl;
38
        }
39
        return 0;
40
}
1
% ./a.out
2
Line 1
3
Line 2
4
Line 3
5
---
6
Line 1
7
Line 2
8
Line 3

Derzeit liebäugle ich mit der Variante in g(), da ich while(1) und 
for(;;) optisch nicht so schön finde.

Wie macht ihr sowas?
Gast
Oliver S. schrieb:
> einfacher auf eof prüfen

Das sollte doch eigentlich getline() machen. Trotzdem stürtzt mir der PC 
ab, wenn ich den String nicht vorher selber lösche. Was eigentlich auch 
getline() machen sollte!?

Thomas K. schrieb:
> keinen Stringvergleich machen sondern die Methode empty()
> bemühen

Danke, das gefällt mir gut.

Dann sehen die Schleifen folgendermaßen aus, wobei mir immernoch g() 
besser gefällt. Kennt ihr noch mehr Möglichkeiten solche Schleifen in 
C++ auszudrücken. Oder auch zu Formatieren. In Ada gibts das ja built 
in.

f()
1
while (1) {
2
        s.clear ();
3
        getline (is, s);
4
        if (s.empty ()) {
5
                break;
6
        }
7
        v.push_back (s);
8
}

g()
1
for (   string s;
2

3
        s.clear (),
4
        getline (is, s),
5
        !s.empty ();
6
    ) {
7
        v.push_back (s);
8
}

Input
1
string s = "Line 1\nLine 2";

Output
1
% ./a.out
2
Line 1
3
Line 2
4
---
5
Line 1
6
Line 2
Gast
Wilhelm M. schrieb:
> &&

Sehr schön. Jetzt prüft es auch explizit auf EOF.

Dirk K. schrieb:
> Frank M. schrieb:
>> Warum packst Du das v.push_back(s) nicht auch noch hinter das letzte
>> Semikolon der for-Zeile?
>
> Wozu sollte das gut sein? Der Lesbarkeit dient es nicht...

Doch ich finde schon. Weil es die geschweiften Klammern spart.
1
for (
2
        string s;
3

4
        s.clear (),
5

6
        getline (is, s) &&
7
        !s.empty ();
8

9
        v.push_back (s)
10
    );
Wobei ich das eher generisch machen würde:
1
template<typename T, typename P>
2
auto read_if(std::istream& is, P predicate) {
3
    std::vector<T> v;
4
    for(T item{}; getline(is, item) && predicate(item);) {
5
        v.push_back(item);
6
    } 
7
    return v;
8
}

und dann:
1
int main () {
2
    std::string s{"Line 1\nLine 2\nLine 3\n\nLine 5"};
3
    std::istringstream iss1{s};
4
    for (const auto& a: read_if<std::string>(iss1, [](const auto& s){return !s.empty();})) {
5
        cout << a << endl;
6
    }
7
}
Gast
Wilhelm M. schrieb:
> leo schrieb:
>> Ja, schaut sehr uebersichtlich und lesbar aus ;-) Der W. schafft es doch
>> immer den Obfuscation-Wettbewert zu gewinnen.
>
> Das hängt immer zu 50% vom Leser ab ;-)

Yep. Meine Erfahrung sagt mir a) die weitaus meiste Zeit verbringe ich 
mit Lesen von Code und b) kuerzerer Code ist lesbarer und verbirgt 
weniger Fehler.

leo
Gast
Wilhelm M. schrieb:
> eher generisch machen

Wie hältst du es mit den ganzen Strings?

Wenn ich etwas generisch machen will dann kommt meist etwas heraus was 
dem folgenden strukturell recht ähnlich sieht. Und ich erwische mich 
dabei, wie ich schon längst aufgehöhrt habe an meinem Programm zu 
arbeiten, sondern eigentlich am Compiler bastel.

Dann nehm ich meist einfach wieder nur char und string.
1
template <typename P
2
        , typename CharT
3
        , typename Traits = char_traits <CharT>
4
        , typename Allocator = allocator <CharT>
5
        , typename S = basic_string <CharT, Traits, Allocator>
6
        , typename V = vector <S>>
7
V h (basic_istream <CharT, Traits>& is, P predicate) {
8
        V v;
9
        for (
10
                   S s
11
                ;  s.clear ()
12
                ,  getline (is, s)
13
                && predicate (s)
14
                ;  v.push_back (s)
15
        );
16
        return v;
17
}

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.