Modernes C++ programmieren

Okt 20, 2024

listings-Chap10-README-onepage.md

Listings of Chap10.docx

This is the list of listings on one page. You can also view a linked summary.

Listing 10.1: Respond to many states with different types of return values.

Book listing lst-0001-book.cpp:

// https://godbolt.org/z/EWqqGjnnz 
#include <iostream>  // cout, cerr
#include <fstream>
#include <vector>
#include <string>
using std::vector; using std::string; using std::cout; using std::cerr;

int countWords(const string& filename) {  // return negative on error
    std::ifstream file{filename};
    if(!file) {     // was there an error opening the file?
        cerr << "Error opening " << filename << "\n";
        return -1;  // report an error to the caller using a special value
    }
    int count = 0;
    string word;
    while(!file.eof()) {      // not at the end yet?
        file >> word;
        ++count;
    }
    return count-1;           // one more word was read at EOF
}
bool process(const vector<string>& args) { // return true if all okay
    if(args.size() == 0) {   // expecting parameters
        cerr << "Command line argument missing\n";
        return false;        // report an error via return
    } else {
        bool result = true;  // for the final result
        for(const string filename : args) {
            cout << filename << ": ";
            int count = countWords(filename);
            if(count < 0) {  // special return indicates error
                cout << "Error!\n";
                result = false;        // at least one error
            } else {
                cout << count << "\n"; // output normal result
            }
        }
        return result;                 // return overall result
    }
}

int main(int argc, const char* argv[]) {
    bool result = process(             // return value contains error indicator
        {argv+1, argv+argc} );         // const char*[] to vector<string>
    if(result) {                       // evaluate return value
        return 0;
    } else {
        cerr << "An error occurred.\n";
        return 1;                      // indicate error externally
    }
}

Godbolt Listing lst-0001-godb.cpp, https://godbolt.org/z/EWqqGjnnz:

//#(compile) c++; compiler:g141; options:; libs:-
// https://godbolt.org/z/EWqqGjnnz 
#include <iostream>  // cout, cerr
#include <fstream>
#include <vector>
#include <string>
using std::vector; using std::string; using std::cout; using std::cerr;

int countWords(const string& filename) {  // return negative on error
    std::ifstream file{filename};
    if(!file) {     // was there an error opening the file?
        cerr << "Error opening " << filename << "\n";
        return -1;  // report an error to the caller using a special value
    }
    int count = 0;
    string word;
    while(!file.eof()) {      // not at the end yet?
        file >> word;
        ++count;
    }
    return count-1;           // one more word was read at EOF
}
bool process(const vector<string>& args) { // return true if all okay
    if(args.size() == 0) {   // expecting parameters
        cerr << "Command line argument missing\n";
        return false;        // report an error via return
    } else {
        bool result = true;  // for the final result
        for(const string filename : args) {
            cout << filename << ": ";
            int count = countWords(filename);
            if(count < 0) {  // special return indicates error
                cout << "Error!\n";
                result = false;        // at least one error
            } else {
                cout << count << "\n"; // output normal result
            }
        }
        return result;                 // return overall result
    }
}

int main(int argc, const char* argv[]) {
    bool result = process(             // return value contains error indicator
        {argv+1, argv+argc} );         // const char*[] to vector<string>
    if(result) {                       // evaluate return value
        return 0;
    } else {
        cerr << "An error occurred.\n";
        return 1;                      // indicate error externally
    }
}

Listing 10.2: Exceptions are triggered with “throw” and handled with “try-catch”.

Book listing lst-0002-book.cpp:

// https://godbolt.org/z/j8abxvvvo 
#include <iostream>            // cout, cerr
#include <vector>
#include <string>
#include <fstream>             // ifstream
#include <stdexcept>           // invalid_argument
using std::vector; using std::string; using std::cout; using std::ifstream;
size_t countWords(const string& filename) { // 0 or greater
    std::ifstream file{};      // create unopened
    // register for exceptions:
    file.exceptions(ifstream::failbit | ifstream::badbit);
    file.open(filename);       // could throw an exception
    size_t count = 0;
    string word;
    file.exceptions(ifstream::badbit); // EOF no longer an exception
    while(!file.eof()) {       // not at the end yet?
        file >> word;   ++count;
    }
    return count-1;            // one more word was read at EOF
}
void process(const vector<string>& args) {
    if(args.size() == 0) {     // process expects parameters
        throw std::invalid_argument{"Command line argument missing"}; // trigger
    } else {
        for(const string filename : args) {
            cout << filename << ": " << countWords(filename) << std::endl;
        }
    }
}
int main(int argc, const char* argv[]) {
    try {                                      // block with error handling
        process(
          vector<string>{argv+1, argv+argc} ); // const char*[] to vector<string>
        return 0;
    } catch(std::exception &exc) {             // error handling
        std::cerr << "An error occurred: " << exc.what() << "\n";
        return 1;
    }
}

Godbolt Listing lst-0002-godb.cpp, https://godbolt.org/z/j8abxvvvo:

//#(compile) c++; compiler:g141; options:; libs:-
// https://godbolt.org/z/j8abxvvvo 
#include <iostream>            // cout, cerr
#include <vector>
#include <string>
#include <fstream>             // ifstream
#include <stdexcept>           // invalid_argument
using std::vector; using std::string; using std::cout; using std::ifstream;
size_t countWords(const string& filename) { // 0 or greater
    std::ifstream file{};      // create unopened
    // register for exceptions:
    file.exceptions(ifstream::failbit | ifstream::badbit);
    file.open(filename);       // could throw an exception
    size_t count = 0;
    string word;
    file.exceptions(ifstream::badbit); // EOF no longer an exception
    while(!file.eof()) {       // not at the end yet?
        file >> word;   ++count;
    }
    return count-1;            // one more word was read at EOF
}
void process(const vector<string>& args) {
    if(args.size() == 0) {     // process expects parameters
        throw std::invalid_argument{"Command line argument missing"}; // trigger
    } else {
        for(const string filename : args) {
            cout << filename << ": " << countWords(filename) << std::endl;
        }
    }
}
int main(int argc, const char* argv[]) {
    try {                                      // block with error handling
        process(
          vector<string>{argv+1, argv+argc} ); // const char*[] to vector<string>
        return 0;
    } catch(std::exception &exc) {             // error handling
        std::cerr << "An error occurred: " << exc.what() << "\n";
        return 1;
    }
}

Listing 10.3: A “catch” can also be within a loop.

Book listing lst-0003-book.cpp:

void process(const vector<string>& args) {
    if(args.size() == 0) {                 // expect parameters
        throw std::invalid_argument{"Command line argument missing"};
    } else {
        for(const string filename : args) {
            cout << filename << ": ";
            try {
                cout << countWords(filename) << "\n";
            } catch(std::exception &exc) {
                cout << "Error: " << exc.what() << "\n";
            }
        }
    }
}

Listing 10.4: Using “throw” without parameters rethrows the currently handled exception.

Book listing lst-0004-book.cpp:

try {
    cout << countWords(filename) << "\n";
} catch(std::exception &exc) {
    cout << "Error: " << exc.what() << "\n";
    throw; // rethrow
}

Listing 10.5: You can also throw exceptions of other types.

Book listing lst-0006-book.cpp:

// https://godbolt.org/z/67cd5bhhE 
#include <string>
#include <iostream> // cout
using std::string; using std::to_string; using std::cout;
void triggerError(int errorCase) {
   try {
       if(errorCase < 10) throw (int)errorCase;
       else if(errorCase < 20) throw 1.0/(errorCase-10.0);
       else throw string{"Error " + to_string(errorCase)};
   } catch(int eval) {
       cout << "int-error: " << eval << "\n";
   } catch(double eval) {
       cout << "double-error: " << eval << "\n";
   } catch(string eval) {
       cout << "string-error: " << eval << "\n";
   }
}
int main() {
    triggerError(3);   // Output: int-error: 3
    triggerError(14);  // Output: double-error: 0.25
    triggerError(50);  // Output: string-error: Error 50
}

Godbolt Listing lst-0006-godb.cpp, https://godbolt.org/z/67cd5bhhE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/67cd5bhhE 
#include <string>
#include <iostream> // cout
using std::string; using std::to_string; using std::cout;
void triggerError(int errorCase) {
   try {
       if(errorCase < 10) throw (int)errorCase;
       else if(errorCase < 20) throw 1.0/(errorCase-10.0);
       else throw string{"Error " + to_string(errorCase)};
   } catch(int eval) {
       cout << "int-error: " << eval << "\n";
   } catch(double eval) {
       cout << "double-error: " << eval << "\n";
   } catch(string eval) {
       cout << "string-error: " << eval << "\n";
   }
}
int main() {
    triggerError(3);   // Output: int-error: 3
    triggerError(14);  // Output: double-error: 0.25
    triggerError(50);  // Output: string-error: Error 50
}

Listing 10.6: At least output the error type and text instead of letting your program tumble out of “main”.

Book listing lst-0007-book.cpp:

// https://godbolt.org/z/TsP33njar 
#include <iostream>
#include <stdexcept> // exception

int main() {
    try {
        // … your other code …
    } catch(std::exception& exc) {
        std::cerr << "main: " << exc.what() << "\n";
    }
}

Godbolt Listing lst-0007-godb.cpp, https://godbolt.org/z/TsP33njar:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TsP33njar 
#include <iostream>
#include <stdexcept> // exception

int main() {
    try {
        // … your other code …
    } catch(std::exception& exc) {
        std::cerr << "main: " << exc.what() << "\n";
    }
}