Chapter 6. Statements

来源:互联网 发布:mpg格式转换软件 编辑:程序博客网 时间:2024/05/29 16:39


Section 6.1. Simple Statements
    Nothing.
Section 6.2. Declaration Statements
    Nothing
Section 6.3. Compound Statements(Blocks)
    Just as there is a null statement, we also can define an empty block. We do so by using a pair of curlies with no statements:
        while (cin >> s && s != sought)
            { } // empty block
Exercises Section 6.3
    6.1: What is a null statement? Give an example of when you might use a null statement.
    Answer:
        a single semicolon, the semicolon means that is a statement, but before this semicolon is nothing, means this statement do nothing.
    For example:
        while(++i != 20)
        ;
        make i == 20
       
    6.2: What is a block? Give an example of when you might use a block.
    Answer:
        a (possibly empty) sequence of statements surrounded by a pair of curly braces.
    For example:
        for(int i = 0; i < 100; ++i)
        {
            cout << "i == " << i << endl;
            cout << "i * i == " << i * i << endl;
        }
       
    6.3: Use the comma operator (Section 5.9, p. 168) to rewrite the else branch in the while loop from the bookstore problem so that it no longer requires a block. Explain whether this rewrite improves or diminishes the readability of this code.
    Here is the code:
        while(std::cin >> trans)
            if(total.same_isbn(trans))
                total += trans;
            else
                std::cout << total << std::endl, total = trans;
    Diminishes the readability actually.
   
    6.4: In the while loop that solved the bookstore problem, what effect, if any, would removing the curly brace following the while and its corresponding close curly have on the program?
    Answer:
        No effect. cause after the keyword while and test condition in brace, it is a block, not several blocks.
       
Section 6.4. Statement Scope
    Nothing
   
Section 6.5. The if Statement
    Nothing

Exercises Section 6.5.1
    6.5: Correct each of the following:
         (a) if (ival1 != ival2)
                  ival1 = ival2
             else ival1 = ival2 = 0;

         (b) if (ival < minval)
                  minval = ival;  // remember new minimum
                  occurs = 1;     // reset occurrence counter

         (c) if (int ival = get_value())
                  cout << "ival = " << ival << endl;
             if (!ival)
                  cout << "ival = 0\n";

         (d) if (ival = 0)
                  ival = get_value();
    Answer:
        (a) if(ival1 !+ ival2)
            {
                ival1 = ival2;
            }
            else
            {
                ival1 = ival2 = 0;
            }
        (b) if(ival < minval)
            {
                minval = ival;
                occurs = 1;
            }
        (c) if(int ival = get_value())
            {
                cout << "ival == " << ival << endl;
            }
            else
            {
                cout << "ival == 0 \n";
            }
        (d) if( ival == 0)
            {
                ival = getline();
            }
           
    6.6: What is a "dangling else"? How are else clauses resolved in C++?
    Answer:
        when a statement contains more if clauses than else clauses. The question then arises: To which if does each else clause belong? These else statement is called [dangling else]
        the dangling else clauses belongs to the nearest if clauses.
       
Section 6.6. The switch Statement
    A label may not stand alone; IT MUST PRECEDE A STATEMENT. If a switch ends with the default case in which there is no work to be done, then the default label MUST BE FOLLOWED BY A NULL STATEMENT.

    Variables can be defined following only the last case or default label:
        case true:
            // error: declaration precedes a case label
            string file_name = get_file_name();
            break;
        case false:
            // ...
    The reason for this rule is to prevent code that might jump over the definition and initialization of a variable.
   
    If we need to define a variable for a particular case, we can do so by defining the variable inside a block, thereby ensuring that the variable can be used only where it is guaranteed to have been defined and initialized:
        case true:
            {
                // ok: declaration statement within a statement block
                string file_name = get_file_name();
                // ...
            }
        break;
            case false:
                // ...
Exercises Section 6.6.5
    6.7: There is one problem with our vowel-counting program as we've implemented it: It doesn't count capital letters as vowels. Write a program that counts both lower- and uppercase letters as the appropriate vowelthat is, your program should count both 'a' and 'A' as part of aCnt, and so forth.
    6.8: Modify our vowel-count program so that it also counts the number of blank spaces, tabs, and newlines read.
    6.9: Modify our vowel-count program so that it counts the number of occurrences of the following two-character sequences: ff, fl, and fi.
    Here is the code of 6.7&6.8&6.9, it's not a good version, but it works:
        #include <iostream>

        int main(void)
        {
            using std::cin;
            using std::cout;
            using std::endl;

            char ch;
            int acount= 0;
            int ocount=0;
            int ecount=0;
            int icount=0;
            int ucount=0;
            int vcount=0;

            int spacecount=0;
            int tabcount=0;
            int newlinecount=0;

            int f1count = 0;
            int ficount = 0;
            int ffcount = 0;


            while ((ch = getchar()) != EOF)
            {
                switch (ch)
                {
                case 'A':
                case 'a':
                    ++acount;
                    break;
                case 'o':
                case 'O':
                    ++ocount;
                    break;
                case 'e':
                case 'E':
                    ++ecount;
                    break;
                case 'i':
                case 'I':
                    ++icount;
                    break;
                case 'u':
                case 'U':
                    ++ucount;
                    break;
                case 'v':
                case 'V':
                    ++vcount;
                    break;
                case ' ':
                    ++spacecount;
                    break;
                case '\t':
                    ++tabcount;
                    break;
                case '\n':
                    ++newlinecount;
                    break;
                case 'f':
                    {
                        char next;
                        while ((next = getchar()) != EOF)
                        {
                            if (next == 'f')
                            {
                                ++ffcount;
                                continue;
                            }
                            else
                            {
                                switch (next)
                                {
                                case '1':
                                    ++f1count;
                                    break;
                                case 'i':
                                    ++ficount;
                                    ++icount;
                                    break;
                                case 'A':
                                case 'a':
                                    ++acount;
                                    break;
                                case 'o':
                                case 'O':
                                    ++ocount;
                                    break;
                                case 'e':
                                case 'E':
                                    ++ecount;
                                    break;
                                case 'I':
                                    ++icount;
                                    break;
                                case 'u':
                                case 'U':
                                    ++ucount;
                                    break;
                                case 'v':
                                case 'V':
                                    ++vcount;
                                    break;
                                case ' ':
                                    ++spacecount;
                                    break;
                                case '\t':
                                    ++tabcount;
                                    break;
                                case '\n':
                                    ++newlinecount;
                                    break;
                                default:
                                    break;
                                }
                                break;
                            }
                        }
                    }
                default:
                    break;
                }
            }

            cout << "acount == " << acount << endl;
            cout << "ocount == " << ocount << endl;
            cout << "ecount == " << ecount << endl;
            cout << "icount == " << icount << endl;
            cout << "ucount == " << ucount << endl;
            cout << "vcount == " << vcount << endl;
            cout << "ffcount == " << ffcount << endl;
            cout << "ficount == " << ficount << endl;
            cout << "f1count == " << f1count << endl;
            cout << "spacecount == " << spacecount << endl;
            cout << "tabcount == " << tabcount << endl;
            cout << "newlinecount == " << newlinecount << endl;

            return 0;
        }
       
    6.10: Each of the programs in the highlighted text on page 206 contains a common programming error. Identify and correct each error.
         (a) switch (ival) {
                 case 'a': aCnt++;
                 case 'e': eCnt++;
                 default: iouCnt++;
             }

         (b) switch (ival) {
                 case 1:
                     int ix = get_value();
                     ivec[ ix ] = ival;
                     break;
                 default:
                     ix = ivec.size()-1;
                     ivec[ ix ] = ival;
             }

         (c) switch (ival) {
                 case 1, 3, 5, 7, 9:
                     oddcnt++;
                     break;
                 case 2, 4, 6, 8, 10:
                     evencnt++;
                     break;
             }

         (d) int ival=512 jval=1024, kval=4096;
             int bufsize;
             // ...
             switch(swt) {
                 case ival:
                     bufsize = ival * sizeof(int);
                     break;
                 case jval:
                     bufsize = jval * sizeof(int);
                     break;
                 case kval:
                     bufsize = kval * sizeof(int);
                     break;
             }
    Answer:
        (a) switch(ival)
            {
            case 'a': aCnt++; break;
            case 'e': eCnt++; break;
            default: iouCnt++; break;
            }
        (b) switch(ival)
            {
            case 1:
                {
                    int ix = get_value();
                    ivec[ix] = ival;
                    break;
                }
            default
                {
                    int ix = ivec.size() - 1;
                    ivec[ix] = ival;
                    break;
                }
            }
        (c) switch(ival)
            {
                case 1:
                case 3:
                case 5:
                case 7:
                case 9:
                    oddcnt++;
                    break;
                case 2:
                case 4:
                case 6:
                case 8:
                case 10:
                    evencnt++;
                    break;
                default:
                    break;
            }
        (d) int ival=512 jval=1024, kval=4096;
            int bufsize;
            // ...
            while(1)
            {
                if(swt == ival)
                {
                    bufsize = ival * sizeof(int);
                    break;
                }
                else if(swt = jval)
                {
                    bufsize = jval * sizeof(int);
                    break;
                }
                else if(swt = kval)
                {
                    bufsize = kval * sizeof(int);
                    break;
                }
                else
                {
                    cerr << "Worng value of swt" << endl;
                    return -1;
                }
            }

Section 6.7. The While Statement
    Nothing
Exercises Section 6.7
    6.11: Explain each of the following loops. Correct any problems you detect.
         (a) string bufString, word;
             while (cin >> bufString >> word) { /* ... */ }

         (b) while (vector<int>::iterator iter != ivec.end())
             {/*... */ }

         (c) while (ptr = 0)
                 ptr = find_a_value();

         (d) while (bool status = find(word))
             { word = get_next_word(); }
             if (!status)
                  cout << "Did not find any words\n";
    Answer:
        (a) while(cin >> word)
            {
                bufString += word;
                // ...
            }
        (b) vector<int>::iterator iter = ivec.begin();
            while(iter != ivec.end())
            {
                // ...
            }
        (c) while(ptr == 0)
                prt = find_a_value;
        (d) I didn't get the mean.May be it should be like this:
            world = get_first_word();
            while(find(word))
            {
                word = get_next_word();
            }
            cout << "Can not find any word of " << word << " in this atricle" << endl;
       
    6.12 Write a small program to read a sequence of strings from standard input looking for duplicated words. The program should find places in the input where one word is followed immediately by itself. Keep track of the largest number of times a single repetition occurs and which word is repeated. Print the maximum number of duplicates, or else print a message saying that no word was repeated. For example, if the input is
        how, now now now brown cow cow
    the output should indicate that the word "now" occurred three times.
    Here is the code:
        #include <iostream>
        #include <string>
        #include <vector>
        #include <cctype>

        bool read_a_word(std::string & word);
        bool find_a_word(std::vector<std::string> & words, std::string word, std::vector<int> & count);
        void print_result(const std::vector<std::string> & words, const std::vector<int> & count);

        int main(void)
        {
            using std::vector;
            using std::string;
            using std::cout;
            using std::endl;

            cout << "Please enter an article ended by a [EOF] character([CTRL + Z]) in a newline, \nthis program will analysis the words in it:" << endl;

            string word;            // a buffer
            vector<string> words;   // a bunch of different word
            vector<int> count;      // the count of each word in words

            while (read_a_word(word))
                find_a_word(words, word, count);

            print_result(words, count);


            return 0;
        }

        // get a single word from stream
        bool read_a_word(std::string & word)
        {
            word = "";      // clear word

            char ch;
            while (ch = getchar())
            {
                if (ch == EOF)      // if get EOF before get any useful character
                    return false;   // that means fail to read a word, return false
                if (isalpha(ch))    // if get a useful character, exit this loop
                    break;          // that means this character is the head of a word
            }

            word += ch;
            while (ch = getchar())
            {
                if (isalpha(ch))    // if the next following character is useful, add it to word
                    word += ch;     // loop again
                else                // if get an unuseful character, that means this word is over
                    break;          // exit the loop
            }

            return true;            // if the program can run to this statement, means get something at least a character in word
                                    // return true indicates the read action is successful.
        }

        // try to find a word in a vector<string> object storing a bunch of word
        // if there it is, add the count of this word in vector<int> object, and return true
        // if can not find this word in the object,add this word to this object and return false;
        bool find_a_word(std::vector<std::string> & words, std::string word, std::vector<int> & count)
        {
            std::vector<std::string>::iterator Witer = words.begin();
            std::vector<int>::iterator Iiter = count.begin();

            for (; Witer != words.end(); ++Witer, ++Iiter)
            {
                if (*Witer == word)         // we found it
                {
                    ++(*Iiter);
                    return true;
                }
            }

            if (Witer == words.end())       // means we can not found it
            {
                words.push_back(word);      // add this new word in
                count.push_back(1);         // record it's count

                return false;
            }
        }

        void print_result(const std::vector<std::string> & words, const std::vector<int> & count)
        {
            std::vector<std::string>::const_iterator Witer = words.begin();
            std::vector<int>::const_iterator Iiter = count.begin();

            std::cout << "There is " << words.size() << " word(s) in this article" << std::endl;
            std::cout << "Here is the statistic result:" << std::endl;

            for (; Witer != words.end(); ++Witer, ++Iiter)
                std::cout << "\t" << *Witer << " == " << *Iiter << " time(s)" << std::endl;
        }
    I made it a little bit complicated.
   
    6.13: Explain in detail how the statement in the while loop is executed:
        *dest++ = *source++;
    Answer:
        This is a classic example. This expression is equivalent to
        {
            *dest = *source;
            ++dest;
            ++source;
        }
       
Section 6.8. The for Loop Statement
    Nothing.
   
Exercises Section 6.8.2
    6.14: Explain each of the following loops. Correct any problems you detect.
         (a) for (int *ptr = &ia, ix = 0;
                   ix != size && ptr != ia+size;
                   ++ix, ++ptr)   { /* ... */ }
         (b) for (; ;) {
                   if (some_condition) return;
                   // ...
             }
         (c) for (int ix = 0; ix != sz; ++ix) { /* ... */ }
             if (ix != sz)
                  // ...
         (d) int ix;
             for (ix != sz; ++ix) { /* ... */ }
         (e) for (int ix = 0; ix != sz; ++ix, ++ sz) { /* ... */ }
    Answer:
        (a) for( int *ptr = ia, ix = 0; ix != size && prt != ia+size; ++ix, ++ptr)
            {...}
        (b) for(; 1; )
            {if(some_condition) return ;}
        (c) int ix;
            for(ix = 0; ix != sz; ++ix)
            {}
            if(ix != sz)
            {...}
        (d) int ix;
            for(ix = 0; ix != sz; ++ix)
            {...}
        (e) for(int ix = 0; ix != sz; ++ix)
            {...}
           
    6.15: The while loop is particularly good at executing while some condition holds; for example, while the end-of-file is not reached, read a next value. The for loop is generally thought of as a step loop: An index steps through a range of values in a collection. Write an idiomatic use of each loop and then rewrite each using the other loop construct. If you were able to program with only one loop, which construct would you choose? Why?
    The while loop commonly used to :
        (1) while(1)
            {
                if(some_condition)
                    break;
            }
        (2) while(cin >> ??)
            {
                ...
            }
    The for loop commonly used to :
        (1) array
        (2) vector<???>
        (3) I know how exactly many times will be loop
    If I am able to program with only one loop, I'll chose while. It's syntax seems like more natural than for
   
    6.16: Given two vectors of ints, write a program to determine whether one vectors is a prefix of the other. For vectors of unequal length, compare the number of elements of the smaller vector. For example, given the vectors (0,1,1,2) and (0,1,1,2,3,5,8), your program should return true.
    Answer:
        #include <iostream>
        #include <vector>

        int main(void)
        {
            using std::cin;
            using std::cout;
            using std::endl;
            using std::vector;

            vector<int> ivec1;
            vector<int> ivec2;

            int temp;

            cout << "Please enter the elements of ivec1:";
            while (cin >> temp)
            {
                ivec1.push_back(temp);
                if (getchar() == '\n')
                    break;
            }

            cout << "Please enter the elements of ivec2:";
            while (cin >> temp)
            {
                ivec2.push_back(temp);
                if (getchar() == '\n')
                    break;
            }
            vector<int>::const_iterator iter1 = ivec1.begin();
            vector<int>::const_iterator iter2 = ivec2.begin();
            for (; iter1 != ivec1.end() && iter2 != ivec2.end(); ++iter1, ++iter2)
            {
                if (*iter1 != *iter2)
                {
                    cout << "ivec1 and ivec2 is two totally different vector<int> object" << endl;
                    return -1;
                }
            }

            if (iter1 == ivec1.end())
                cout << "ivec1 is ivec2's child" << endl;

            if (iter2 == ivec2.end())
                cout << "ivec2 is ivec1's child" << endl;

            return 0;
        }
       
Section 6.9. The do while Statement
    Unlike a while statement, a do-while statement always ends with a semicolon.
        do
                statement
        while   (condition);

Exercises Section 6.9:
    6.17: Explain each of the following loops. Correct any problems you detect.
        (a) do
                int v1, v2;
                cout << "Please enter two numbers to sum:" ;
                cin >> v1 >> v2;
                if (cin)
                    cout << "Sum is: "
                         << v1 + v2 << endl;
            while (cin);

        (b) do {
                // ...
            } while (int ival = get_response());

        (c) do {
                int ival = get_response();
                if (ival == some_value())
                     break;
            } while (ival);
             if (!ival)
                 // ...
    Answer:
        (a) do
            {
                int v1, v2;
                cout <<"Please enter two numbers to sum:";
                cin >> v1 >> v2;
                if(cin)
                    cout << "Sum is: " << v1+v2 << endl;
                else
                    break;
            }while(1);
        (b) int ival = initial_value();
            do
            {
                //...
            }while(ival = get_response());
        (c) int ival;
            do
            {
                ival = get_response();
                if(ival == some_value())
                    break;
            }while(ival);
           
            if(!ival)
                ...
    6.18: Write a small program that requests two strings from the user and reports which string is lexicographically less than the other (that is, comes before the other alphabetically). Continue to solicit the user until the user requests to quit. Use the string type, the string less-than operator, and a do while loop.
    Here is the code:
        #include <iostream>
        #include <string>

        bool Continue();

        int main(void)
        {
            using std::cin;
            using std::cout;
            using std::endl;
            using std::string;

            string word1, word2;

            do
            {
                cout << "Please enter word1 == ";
                cin >> word1;
                cout << "Please enter word2 == ";
                cin >> word2;

                if (word1 > word2)
                    cout << "word1 > word2" << endl;
                else if (word1 < word2)
                    cout << "word1 < word2" << endl;
                else if (word1 == word2)
                    cout << "word1 == word2" << endl;

                if (!Continue())
                    break;
                else
                    ;// do nothing       
            } while (1);


            return 0;
        }

        bool Continue()
        {
            do{
                std::string str;
                std::cout << "Continue?<Y/N>:";
                std::cin >> str;
                switch (str[0])
                {
                case 'Y':
                case 'y':
                    return true;
                    break;
                case 'N':
                case 'n':
                    return false;
                    break;
                default:
                    break;
                }
            } while (1);

        }
       
Section 6.10. The break Statement
    Nothing
   
Exercises Section 6.10
    6.19: The first program in this section could be written more succinctly. In fact, its action could be contained entirely in the condition in the while. Rewrite the loop so that it has an empty body and does the work of finding the element in the condition.
         vector<int>::iterator iter = vec.begin();
         while (iter != vec.end()) {
            if (value == *iter)
                 break; // ok: found it!
            else
                 ++iter; // not found: keep looking
         }// end of while
         if (iter != vec.end()) // break to here ...
             // continue processing
    Answer:
        vector<int>::iterator iter = vec.begin();
        while(iter != vec.end() && *iter++ != value);
        // *(iter -1 ) == value or iter == vec.end()
        if(iter != vec.end())
            // continue processing
           
    6.20: Write a program to read a sequence of strings from standard input until either the same word occurs twice in succession or all the words have been read. Use a while loop to read the text one word at a time. Use the break statement to terminate the loop if a word occurs twice in succession. Print the word if it occurs twice in succession, or else print a message saying that no word was repeated.
    Here is the code:
        #include <iostream>
        #include <string>

        int main(void)
        {
            using std::cin;
            using std::cout;
            using std::endl;
            using std::string;

            string word, next;

            cout << "Please enter a series of word:";

            while (cin >> next)
            {
                char temp = getchar();
                if (next == word)
                {
                    cout << next << endl;
                    break;
                }
                else
                    word = next;

                if (temp == '\n')
                    break;
            }

            cout << "they are all different" << endl;

            return 0;
        }
       
Section 6.11. The continue Statement
    Nothing new;
 
Exercises Section 6.11
    6.21: Revise the program from the last exercise in Section 6.10 so that it looks only for duplicated words that start with an uppercase letter.
    Here is the code:
        #include <iostream>
        #include <string>
        #include <cctype>

        int main(void)
        {
            using std::cin;
            using std::cout;
            using std::endl;
            using std::string;

            string word, next;

            cout << "Please enter a series of word:";

            while (cin >> next)
            {
                if (islower(next[0]))
                    continue;
                else
                {
                    if (word == next)
                    {
                        cout << word << endl;
                        return 0;
                    }
                    else
                        word = next;
                }

            }

            cout << "they are all different" << endl;

            return 0;
        }
       
Section 6.12. The goto Statement
    This is shit.
   
Exercises Section 6.12
    Also Shit.

Section 6.13. try Blocks and Exception Handling *************VERY IMPORTANT
    (1) use [throw expressions] to Create an error object.
        if(!item1.same_isbn(item2))
            throw std::runtime_error("Data must refer to same ISBN")
        std::cout << item1 + item2 << std::endl;
    std::runtime_error is a class type, the throw statement will create an object of this class type record the information we add, that is a literal string constant ["Data must refer to same ISBN"], but how can we named this object? no, we can not name it, and this is no necessary, we'll see why in the following text.
   (2) use catch to handle the error object;
        while (std::cin >> item1 >> item2)
        {
            try{
                if (!item1.same_isbn(item2))
                    throw std::runtime_error("Data must refer to same ISBN");
                else
                    throw std::runtime_error("everything is ok");
            }
            catch (std::runtime_error err)
            {
                std::cout << err.what() << std::endl;
            }
        }
    where did the throw statement deliver the object of type std::runtime_error to? The answer is catch clauses. the catch clauses will handle the error we throw from try block.
    In the fragment above, we throw an object of std::runtime_error object to the following catch clauses, and the first(there should be more, but in this case, we coding only one catch) catch receive an std::runtime_error object, alike to some function, the value of object which we throw will assign to [err], now [catch] knows what had happened.
    in catch block, we use a method of err, that is what(), this method returns the string in err, so we can print it.
    (3) what if we try to throw two error object?
        while (std::cin >> item1 >> item2)
        {
            try{
                    throw std::runtime_error("Data must refer to same ISBN");
                    throw std::overflow_error("everything is ok");
            }
            catch (std::runtime_error err)
            {
                std::cout << err.what() << std::endl;
            }
            catch (std::overflow_error err1)
            {
                std::cout << err1.what() << std::endl;
            }
        }
    the second throw statement doesn't work..so we can only throw one error object in one try block.
    (4) the error object commonly created by the compiler, not in manual. like this:
        #include <iostream>
        #include <bitset>

        int main(void)
        {
            try{
                std::bitset<128> hugenumber;
                hugenumber[0] = 1;
                hugenumber[127] = 1;
                unsigned long notHugeEnough = hugenumber.to_ulong();
            }
            catch (std::overflow_error err)
            {
                std::cout << err.what() << std::endl;
            }

            return 0;
        }

Exercises Section 6.13.2
    6.23: The bitset operation to_ulong throws an overflow_error exception if the bitset is larger than the size of an unsigned long. Write a program that generates this exception.
    Answer:
        #include <iostream>
        #include <bitset>

        int main(void)
        {
            try{
                std::bitset<128> hugenumber;
                hugenumber[0] = 1;
                hugenumber[127] = 1;
                unsigned long notHugeEnough = hugenumber.to_ulong();
            }
            catch (std::overflow_error err)
            {
                std::cout << err.what() << std::endl;
            }

            return 0;
        }
       
    6.24: Revise your program to catch this exception and print a message.
    Answer:
        We've done it yet.
       
    (5) Standard Exceptions
    The C++ library defines a set of classes that it uses to report problems encountered in the functions in the standard library. These standard exception classes are also intended to be used in the programs we write. Library exception classes are defined in four headers:
        (1) The <exception> header defines the most general kind of exception class named exception. IT COMMUNICATES ONLY THAT AN EXCEPTION OCCURS BUT PROVIDES NO ADDITIONAL INFORMATION.
        (2) The <stdexcept> header defines several general purpose exception classes.
        (3) The <new> header defines the [bad_alloc] exception type, which is the exception thrown by new (Section 5.11, p. 174) if it cannot allocate memory.
        (4) The <type_info> header defines the bad_cast exception type, which we will discuss in Section 18.2.
    All these error classes are in the namespace std::.
        (5) The library exception classes have only a few operations. We can create, copy, and assign objects of any of the exception types. The exception, bad_alloc, and bad_cast types define only a default constructor; IT IS NOT POSSIBLE TO PROVIDE AN INITIALIZER FOR OBJECTS OF THESE TYPES. The other exception types define ONLY A SINGLE CONSTRUCTOR THAT TAKES A STRING INITIALIZER. When we define any of these other exception types, we MUST supply a string argument. That string initializer is used to provide additional information about the error that occurred.
    You'd better include the proper headers when you have to write the error handle program, don't be like the above program I wrote.
   
Section 6.14. Using the Preprocessor for Debugging
    In Section 2.9.2 we learned how to use preprocessor variables to prevent header files being included more than once. C++ programmers sometimes use a technique similar to header guards to conditionally execute debugging code.
        int main()
        {
        #ifndef NDEBUG
        cerr << "starting main" << endl;
        #endif
        // ...
    By default, NDEBUG is not defined, meaning that by default, the code inside the #ifndef and #endif is processed. When the program is being developed, we leave NDEBUG undefined so that the debugging statements are executed. When the program is built for delivery to customers, these debugging statements can be (effectively) removed by defining the NDEBUG preprocessor variable.
    Most compilers provide a command line option that defines NDEBUG
        (1) *nix
            CC -DNDEBUG main.C
        (2) Visual Studio 2013
            [ALT + F7] --> [C/C++] --> [CommandLine], add [-DNDEBUG] in
    The above way to defines NDEBUG has the same effect as writing #define NDEBUG at the beginning of main.C.
   
    The preprocessor defines four other constants that can be useful in debugging:
        (1) __FILE__
            name of the file.
        (2) __LINE__
            current line number.
        (3) __TIME__
            time the file was compiled
        (4) __DATE__
            date the file was compiled.
    We might use these constants to report additional information in error messages:
        #include <iostream>
        #include <string>

        int main(void)
        {
            std::string word;
            std::cout << "Please enter a word :";
            std::cin >> word;
            if (word.size() < 50)
            {
                std::cerr << "ERROR, here is the error information" << std::endl;
                std::cerr << "File :[" << __FILE__ << "]" << std::endl;
                std::cerr << "Line :[" << __LINE__ << "]" << std::endl;
                std::cerr << "Time :[" << __TIME__ << "]" << std::endl;
                std::cerr << "Date :[" << __DATE__ << "]" << std::endl;
            }
            return 0;
        }
    If we give this program a string that is shorter than 50, then the following error message will be generated:
        Please enter a word :abcd
        ERROR, here is the error information
        File :[c:\users\fosen\documents\visual studio 2013\projects\c++ primer\c++ primer\main.cpp]
        Line :[13]
        Time :[19:30:06]
        Date :[Jan 30 2015]

    Another common debugging technique uses the [NDEBUG] preprocessor variable and the [assert] [preprocessor macro]. The assert macro is defined in the <cassert> header, which we must include in any file that uses assert.
    A preprocessor macro acts something like a function call. The assert macro takes a single expression, which it uses as a condition:
        assert(expression)
    As long as NDEBUG is not defined, the assert macro evaluates the condition and if the result is false, then assert writes a message and terminates the program. If the expression has a nonzero (e.g., true) value, then assert does nothing.
    Unlike exceptions, which deal with errors that a program expects might happen in production, programmers use assert to test conditions that "CANNOT HAPPEN." For example, a program that does some manipulation of input text might know that all words it is given are always longer than a threshold. That program might contain a statement such as:
        assert(word.size() > threshold);
    ATTENTION: assert() is work with the preprocessor variable that named as [NDEBUG] (if you define a preprocessor variable named as [ABCD] or something else, it doesn't work!!!), if you are already defined [NDEBUG] before you "call" assert(expression); then the assert() will do nothing whether the value of [expression] is true or false. If you don't define [NDEBUG], the assert(expression) will work, if the expression is false, assert will write a message and terminates the program.
    For example:
        #include <iostream>
        #include <string>
        #include <cassert>

        int main(void)
        {
        #ifndef NDEBUG
            std::cerr << "[Starting main]" << std::endl;
        #endif

            std::string word;
            std::cout << "Please enter a word :";
            std::cin >> word;

            assert(word.size() > 5);

            std::cout << "Everything is OK" << std::endl;

            return 0;
        }
    If we run this program without defined NDEBUG in commandline like this:
    (1) input "1234"
        [Starting main]
        Please enter a word :1234
        Assertion failed: word.size() > 5, file c:\users\fosen\documents\visual studio 2013\projects\c++ primer\c++ primer\main.cpp, line 16
    (2) input "123456"
        [Starting main]
        Please enter a word :123456
        Everything is OK
    If we run this program with defined NDEBUG in commandline like this:
    (1) input "1234"
        Please enter a word :1234
        Everything is OK
    (2) input "123456"
        Please enter a word :123456
        Everything is OK
    During testing the assert has the effect of verifying that the data are always of the expected size. Once development and test are complete, the program is built and NDEBUG is defined. In production code, assert does NOTHING, so there is NO run-time cost.
    assert should be used only to verify things that truly should not be possible. It can be useful as an aid in getting a program debugged but should not be used to substitute for run-time logic checks or error checking that the program should be doing.
   
Exercises Section 6.14
    6.25: Revise the program you wrote for the exercise in Section 6.11 (p. 214) to conditionally print information about its execution. For example, you might print each word as it is read to let you determine whether the loop correctly finds the first duplicated word that begins with an uppercase letter. Compile and run the program with debugging turned on and again with it turned off.
    Answer:
        I'm lazy..
       
    6.26: What happens in the following loop:
        string s;
        while (cin >> s) {
           assert(cin);
           // process s
        }
    Explain whether this usage seems like a good application of the assert macro.
    Answer:
        No, assert() does nothing in this case whether NDEBUG is defined or not.
        cause, when the program calls assert(); the cin is true always. when the cin is false, that means [cin >> s] returns a false value, that means INPUT ERROR, that also means the program can not enter the loop...
        so , this kind of usage is absofuckinglutely not a good application of  assert macro.
       
    6.27: Explain this loop:
        string s;
        while (cin >> s && s != sought) { } // empty body
        assert(cin);
        // process s
    Answer:
        That means cin should always be true, the while condition should always be false only because s == sought, if something bad happened make the input error, assert(cin) will terminate this program and print error informations about this crash.

0 0