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

Gast #6173761
Lesenswert?

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 #6173844
Lesenswert?

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 #6173905
Lesenswert?

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
    );
#6173918
Lesenswert?

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 #6173945
Lesenswert?

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 #6173958
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren