C++ Primer exercise 3.13

Discussion in 'C++' started by arnuld, Jul 19, 2007.

  1. arnuld

    arnuld Guest

    i have solved the problem but it is quite length. as usual, i wanted some
    coding-standards or good-design opinions:


    /* C++ Primer 4/e
    * chapter 3 - Library Types

    * exercise 3.13
    * STAMEMENT
    * read a set of integers into the vector. calculate and print the
    sum of each * pair of adjacent elements of the vector. If there is an odd
    number then tell the * user about it and print the value of the last
    element without summing it. *
    */


    #include <iostream>
    #include <vector>

    int main()
    {
    std::vector<int> ivec; /* empty vector */

    int ivec_limit = 11;
    for(int i = 5; i != ivec_limit; ++i) /* inserts itegers */
    ivec.push_back(i);

    /* now we will print the elements of vector */ std::cout << "These are
    the elements of vector:\t"; for(std::vector<int>::const_iterator
    iter=ivec.begin(); iter != ivec.end(); ++iter)
    {
    std::cout << *iter << " ";
    }

    std::cout << std::endl;
    /* actual programme */
    for(std::vector<int>::iterator iter = ivec.begin(); iter != ivec.end();
    ++iter)
    {
    if((*iter % 2) != 0)
    {
    std::cout << "\n"
    << *iter
    << " is an odd number"
    << " not adding it to the total."
    << std::endl;
    if(iter == ivec.begin())
    {
    std::cout << *iter
    << " is the 1st element of vector"
    << std::endl;
    }
    else
    {
    std::cout << "--> last element was: "
    << *(iter - 1)
    << std::endl;
    }
    }
    else
    {
    if((iter + 1) == ivec.end())
    {
    std::cout << "\nLast element of vector is: "
    << *iter
    << std::endl;
    }
    else
    {
    std::cout << "\nAdjacent elements are: "
    << *iter
    << " & "
    << *(iter + 1)
    << "\n--> and their sum is: "
    << *iter + *(iter + 1)
    << std::endl;
    }
    }
    }


    return 0;
    }


    ===== OUTPUT =============
    [arnuld@arch cpp ]% g++ -ansi -pedantic -Wall -Wextra ex_03-13.cpp
    [arnuld@arch cpp ]% ./a.out
    These are the elements of vector: 5 6 7 8 9 10

    5 is an odd number not adding it to the total. 5 is the 1st element of
    vector

    Adjacent elements are: 6 & 7
    --> and their sum is: 13

    7 is an odd number not adding it to the total. --> last element was: 6

    Adjacent elements are: 8 & 9
    --> and their sum is: 17

    9 is an odd number not adding it to the total. --> last element was: 8

    Last element of vector is: 10
    [arnuld@arch cpp ]%



    --
    -- http://arnuld.blogspot.com
    arnuld, Jul 19, 2007
    #1
    1. Advertising

  2. On 2007-07-19 10:35, arnuld wrote:
    > i have solved the problem but it is quite length. as usual, i wanted some
    > coding-standards or good-design opinions:
    >
    >
    > /* C++ Primer 4/e
    > * chapter 3 - Library Types
    >
    > * exercise 3.13
    > * STAMEMENT
    > * read a set of integers into the vector. calculate and print the
    > sum of each * pair of adjacent elements of the vector. If there is an odd
    > number then tell the * user about it and print the value of the last
    > element without summing it. *
    > */


    Sorry, but you have not solved the problem the author intended. First of
    you should let the user enter the numbers. Then you should print the sum
    of each pair of numbers, but if the user entered an odd number of
    numbers you can't sum the last element with another so you you should
    just print it:

    So an example run could look something like this:
    --
    Please enter some numbers:
    1
    2
    3
    4
    5

    You entered an odd number of numbers.

    The sums of the pairs are:
    3
    7
    5
    --
    Or like this:
    --
    Please enter some numbers:
    1
    2
    3
    4
    5
    6

    The sums of the pairs are:
    3
    7
    11

    --
    Erik Wikström
    =?UTF-8?B?RXJpayBXaWtzdHLDtm0=?=, Jul 19, 2007
    #2
    1. Advertising

  3. arnuld

    arnuld Guest

    > On Thu, 19 Jul 2007 09:23:21 +0000, Erik Wikström wrote:


    > Sorry, but you have not solved the problem the author intended. First of
    > you should let the user enter the numbers. Then you should print the sum
    > of each pair of numbers, but if the user entered an odd number of
    > numbers you can't sum the last element with another so you you should
    > just print it:


    ok, BTW, i found the statement ambiguous. so i created the programem on
    that basis of what it could mean.

    > So an example run could look something like this: -- Please enter some
    > numbers:
    > 1
    > 2
    > 3
    > 4
    > 5
    >
    > You entered an odd number of numbers.
    >
    > The sums of the pairs are:
    > 3
    > 7
    > 5


    sorry, after 1.5 hours of grueling work, my new programme still gives
    "segmentatioon fault" on finding an odd list of numbers. for even amount
    of numbers this programme works:

    #include <iostream>
    #include <vector>

    int main()
    {
    std::vector<int> ivec; /* empty vector */ int v_num;

    std::cout << "Please enter some numbers: " << std::endl; while(std::cin
    >> v_num)

    ivec.push_back(v_num);

    if((ivec.size() % 2) != 0)
    {
    std::cout << "oops!, you enetered an odd number of numbers" <<
    std::endl;
    }

    std::cout << "The sum of the pairs are: " << std::endl; /* actual
    programme */
    for(std::vector<int>::const_iterator iter = ivec.begin(); iter !=
    ivec.end(); iter += 2)
    {
    if((iter + 1) == ivec.end())
    {
    std::cout << *iter << std::endl;
    }
    else
    {
    std::cout << *iter + *(iter + 1) << std::endl;
    }
    }

    return 0;
    }


    --
    -- http://arnuld.blogspot.com
    arnuld, Jul 19, 2007
    #3
  4. On 2007-07-19 13:41, arnuld wrote:
    >> On Thu, 19 Jul 2007 09:23:21 +0000, Erik Wikström wrote:

    >
    >
    >> Sorry, but you have not solved the problem the author intended. First of
    >> you should let the user enter the numbers. Then you should print the sum
    >> of each pair of numbers, but if the user entered an odd number of
    >> numbers you can't sum the last element with another so you you should
    >> just print it:

    >
    > ok, BTW, i found the statement ambiguous. so i created the programem on
    > that basis of what it could mean.
    >
    >> So an example run could look something like this: -- Please enter some
    >> numbers:
    >> 1
    >> 2
    >> 3
    >> 4
    >> 5
    >>
    >> You entered an odd number of numbers.
    >>
    >> The sums of the pairs are:
    >> 3
    >> 7
    >> 5

    >
    > sorry, after 1.5 hours of grueling work, my new programme still gives
    > "segmentatioon fault" on finding an odd list of numbers. for even amount
    > of numbers this programme works:
    >
    > #include <iostream>
    > #include <vector>
    >
    > int main()
    > {
    > std::vector<int> ivec; /* empty vector */ int v_num;
    >
    > std::cout << "Please enter some numbers: " << std::endl; while(std::cin
    > >> v_num)

    > ivec.push_back(v_num);
    >
    > if((ivec.size() % 2) != 0)
    > {
    > std::cout << "oops!, you enetered an odd number of numbers" <<
    > std::endl;
    > }
    >
    > std::cout << "The sum of the pairs are: " << std::endl; /* actual
    > programme */
    > for(std::vector<int>::const_iterator iter = ivec.begin(); iter !=
    > ivec.end(); iter += 2)


    Replace the check to a less than (iter < ivec.end()), since you are
    increasing the iterator with 2 each step you will step over ivec.end()
    if the number of elements is odd..

    > {
    > if((iter + 1) == ivec.end())
    > {
    > std::cout << *iter << std::endl;


    Or add break; here.

    > }
    > else
    > {
    > std::cout << *iter + *(iter + 1) << std::endl;
    > }
    > }
    >
    > return 0;
    > }


    --
    Erik Wikström
    =?UTF-8?B?RXJpayBXaWtzdHLDtm0=?=, Jul 19, 2007
    #4
  5. arnuld

    arnuld Guest

    > On Thu, 19 Jul 2007 12:01:55 +0000, Erik Wikström wrote:

    >> On 2007-07-19 13:41, arnuld wrote:
    >> for(std::vector<int>::const_iterator iter = ivec.begin(); iter !=
    >> ivec.end(); iter += 2)


    > Replace the check to a less than (iter < ivec.end()), since you are
    > increasing the iterator with 2 each step you will step over ivec.end()
    > if the number of elements is odd..


    that i never thought of

    >> {
    >> if((iter + 1) == ivec.end())
    >> {
    >> std::cout << *iter << std::endl;


    > Or add break; here.


    this is what i wanted. i supposed and befooled myself into thinking that
    since now test is true only this one statement will execute but i forgot
    about the for loop :(



    --
    -- http://arnuld.blogspot.com
    arnuld, Jul 19, 2007
    #5
  6. arnuld

    Andre Kostur Guest

    =?UTF-8?B?RXJpayBXaWtzdHLDtm0=?= <> wrote in
    news:ToIni.4399$:

    > On 2007-07-19 13:41, arnuld wrote:
    >>> On Thu, 19 Jul 2007 09:23:21 +0000, Erik Wikström wrote:

    >>
    >>
    >>> Sorry, but you have not solved the problem the author intended.
    >>> First of you should let the user enter the numbers. Then you should
    >>> print the sum of each pair of numbers, but if the user entered an
    >>> odd number of numbers you can't sum the last element with another so
    >>> you you should just print it:

    >>
    >> ok, BTW, i found the statement ambiguous. so i created the programem
    >> on that basis of what it could mean.
    >>
    >>> So an example run could look something like this: -- Please enter
    >>> some numbers:
    >>> 1
    >>> 2
    >>> 3
    >>> 4
    >>> 5
    >>>
    >>> You entered an odd number of numbers.
    >>>
    >>> The sums of the pairs are:
    >>> 3
    >>> 7
    >>> 5

    >>
    >> sorry, after 1.5 hours of grueling work, my new programme still gives
    >> "segmentatioon fault" on finding an odd list of numbers. for even
    >> amount of numbers this programme works:
    >>
    >> #include <iostream>
    >> #include <vector>
    >>
    >> int main()
    >> {
    >> std::vector<int> ivec; /* empty vector */ int v_num;
    >>
    >> std::cout << "Please enter some numbers: " << std::endl;
    >> while(std::cin
    >> >> v_num)

    >> ivec.push_back(v_num);
    >>
    >> if((ivec.size() % 2) != 0)
    >> {
    >> std::cout << "oops!, you enetered an odd number of numbers" <<
    >> std::endl;
    >> }
    >>
    >> std::cout << "The sum of the pairs are: " << std::endl; /* actual
    >> programme */
    >> for(std::vector<int>::const_iterator iter = ivec.begin(); iter !=
    >> ivec.end(); iter += 2)

    >
    > Replace the check to a less than (iter < ivec.end()), since you are
    > increasing the iterator with 2 each step you will step over ivec.end()
    > if the number of elements is odd..


    Caveat: this is not good general advice. Testing for != end() is better
    than testing for < end() as it is how one does the same sort of test for
    the other containers. May work for vectors, won't work for the other
    containers.

    Finally, assuming that the += 2 steps past the end() iterator, isn't it
    technically undefined behaviour to make the comparison as you would be
    comparing a pointer to an element within an array (one-past-the-end
    pointer is still considered to be "within the array") to a pointer that
    isn't in the same array (and isn't 0)?

    >> {
    >> if((iter + 1) == ivec.end())
    >> {
    >> std::cout << *iter << std::endl;

    >
    > Or add break; here.


    I think this may be a better choice. Then again, I'd probably using
    indexing for this instead of iteration (which does pretty much tie me to
    vector...). Or perhaps use a while loop instead of a for.

    >> }
    >> else
    >> {
    >> std::cout << *iter + *(iter + 1) << std::endl;
    >> }
    >> }
    >>
    >> return 0;
    >> }

    >
    Andre Kostur, Jul 19, 2007
    #6
  7. arnuld

    James Kanze Guest

    On Jul 19, 2:01 pm, Erik Wikström <> wrote:
    > On 2007-07-19 13:41, arnuld wrote:

    [...]
    > > #include <iostream>
    > > #include <vector>

    >
    > > int main()
    > > {
    > > std::vector<int> ivec; /* empty vector */ int v_num;


    > > std::cout << "Please enter some numbers: " << std::endl; while(std::cin
    > > >> v_num)

    > > ivec.push_back(v_num);


    > > if((ivec.size() % 2) != 0)
    > > {
    > > std::cout << "oops!, you enetered an odd number of numbers" <<
    > > std::endl;
    > > }


    > > std::cout << "The sum of the pairs are: " << std::endl; /* actual
    > > programme */
    > > for(std::vector<int>::const_iterator iter = ivec.begin(); iter !=
    > > ivec.end(); iter += 2)


    > Replace the check to a less than (iter < ivec.end()), since you are
    > increasing the iterator with 2 each step you will step over ivec.end()
    > if the number of elements is odd..


    That won't work either, since you'll still enter the loop when
    there is only one element remaining (and thus add 2, resulting
    in undefined behavior). Interpreting the requirements strictly,
    I'd use something like:

    while ( iter != end && iter + 1 != end ) {
    // ...
    iter +=2 ;
    }
    if ( iter != end ) {
    // odd number...
    }

    Interpreting them a bit more loosely, I'd probably use a vector
    of std::pair< int, int >, and handle the case of an odd number
    of elements at input. (In a real world application, I'd
    probably require two integers per line, and use getline to
    read.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jul 20, 2007
    #7
  8. arnuld

    James Kanze Guest

    On Jul 19, 4:14 pm, Andre Kostur <> wrote:
    > =?UTF-8?B?RXJpayBXaWtzdHLDtm0=?= <> wrote innews:ToIni.4399$:
    > > On 2007-07-19 13:41, arnuld wrote:
    > >>> On Thu, 19 Jul 2007 09:23:21 +0000, Erik Wikström wrote:


    > > Replace the check to a less than (iter < ivec.end()), since
    > > you are increasing the iterator with 2 each step you will
    > > step over ivec.end() if the number of elements is odd..


    > Caveat: this is not good general advice. Testing for != end()
    > is better than testing for < end() as it is how one does the
    > same sort of test for the other containers. May work for
    > vectors, won't work for the other containers.


    Agreed, sort of. It's what one expects, and code should provide
    the least surprises to the reader. But he needs random access
    iterators for the + 1 as well, so the code won't work for other
    containers anyway.

    > Finally, assuming that the += 2 steps past the end() iterator,
    > isn't it technically undefined behaviour to make the
    > comparison as you would be comparing a pointer to an element
    > within an array (one-past-the-end pointer is still considered
    > to be "within the array") to a pointer that isn't in the same
    > array (and isn't 0)?


    It's not only undefined behavior; it crashes with both g++ and
    VC++ when you turn on debugging options. (You should be using
    the debugging options whenever possible, especially when
    learning. Regretfully, code compiled with the debugging options
    is not compatible with code compiled without. The debugging
    options have significant runtime overhead, and a bottleneck
    anywhere in the application means that you can't use them
    anywhere.)

    > >> {
    > >> if((iter + 1) == ivec.end())
    > >> {
    > >> std::cout << *iter << std::endl;


    > > Or add break; here.


    > I think this may be a better choice.


    Using a break to leave a loop is NEVER a good choice.

    > Then again, I'd probably using indexing for this instead of
    > iteration (which does pretty much tie me to vector...). Or
    > perhaps use a while loop instead of a for.


    There's a very nice solution with a while loop:

    while ( iter != ivec.end() ) {
    {
    int first = *iter ++ ;
    if ( iter != ivec.end() ) {
    int second = *iter ++ ;
    std::cout << first + second << std::endl ;
    } else {
    std::cout << "odd number of elements, last was: "
    << first << std::endl ;
    }
    }

    I'm not overly enthusiastic about spreading the increments out
    all over the loop, but it seems preferable here to the
    alternatives. It also avoids the requirement for a random
    access iterator, so you can replace vector with just about any
    container. (I still rather prefer the idea of using a container
    of std::pair, however, and handling the odd case at the end of
    input.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jul 20, 2007
    #8
  9. arnuld

    arnuld Guest

    > On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:
    > Agreed, sort of. It's what one expects, and code should provide the
    > least surprises to the reader. But he needs random access iterators for
    > the + 1 as well, so the code won't work for other containers anyway.


    :-(


    > It's not only undefined behavior; it crashes with both g++ and VC++ when
    > you turn on debugging options. (You should be using the debugging
    > options whenever possible, especially when learning. Regretfully, code
    > compiled with the debugging options is not compatible with code compiled
    > without. The debugging options have significant runtime overhead, and a
    > bottleneck anywhere in the application means that you can't use them
    > anywhere.)


    ok, i have added "-ggdb" to my arsenal :)


    > Using a break to leave a loop is NEVER a good choice.


    and i am the one who always believed that "break" was especially created
    for the purpose of "breaking out of loop".


    > There's a very nice solution with a while loop:
    >
    > while ( iter != ivec.end() ) {
    > {
    > int first = *iter ++ ;
    > if ( iter != ivec.end() ) {
    > int second = *iter ++ ;
    > std::cout << first + second << std::endl ;
    > } else {
    > std::cout << "odd number of elements, last was: "
    > << first << std::endl ;
    > }
    > }
    > }
    > I'm not overly enthusiastic about spreading the increments out all over
    > the loop, but it seems preferable here to the alternatives. It also
    > avoids the requirement for a random access iterator, so you can replace
    > vector with just about any container. (I still rather prefer the idea
    > of using a container of std::pair, however, and handling the odd case at
    > the end of input.)


    James, that is really nice solution, i just loved it :). i always thought
    that "for" loop is the official loop of C++ (like 'C' is the official
    language of GNU, at least to speak) but i see, in this situation "while"
    fits much better.


    --
    -- http://arnuld.blogspot.com
    arnuld, Jul 20, 2007
    #9
  10. arnuld

    Andre Kostur Guest

    arnuld <> wrote in news:pan.2007.07.20.09.46.53.778891
    @gmail.com:

    >> On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:


    [snip]

    >> Using a break to leave a loop is NEVER a good choice.

    >
    > and i am the one who always believed that "break" was especially created
    > for the purpose of "breaking out of loop".


    For that, and switch statements. However it is a tool that is easily
    misused. By using break you are stepping outside of the expected code
    flow. Much like scattering goto's all over your code too. I'm not sure
    that "never" is a good word, but it should probably be avoided where
    possible.

    [snip while solution]

    > James, that is really nice solution, i just loved it :). i always thought
    > that "for" loop is the official loop of C++ (like 'C' is the official
    > language of GNU, at least to speak) but i see, in this situation "while"
    > fits much better.


    There are three looping constructs in C++ language itself... "for",
    "while", and "do..while". Learn them all as each one has certain
    behaviours and makes them better for various situations. Keep in mind that
    each one could be implemented in terms of one of the other ones, but the
    syntax would get awkward and you'd only be obscuring your intent. In
    addition there are other constructs in the Standard Library that do loop-
    like things, such as std::for_each, std::transform, and others.
    Andre Kostur, Jul 20, 2007
    #10
  11. arnuld

    James Kanze Guest

    On Jul 20, 11:46 am, arnuld <> wrote:
    > > On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:


    > > It's not only undefined behavior; it crashes with both g++
    > > and VC++ when you turn on debugging options. (You should be
    > > using the debugging options whenever possible, especially
    > > when learning. Regretfully, code compiled with the
    > > debugging options is not compatible with code compiled
    > > without. The debugging options have significant runtime
    > > overhead, and a bottleneck anywhere in the application means
    > > that you can't use them anywhere.)


    > ok, i have added "-ggdb" to my arsenal :)


    That's not really the "debug" option in the sense I was thinking
    of. That one puts the symbol table information in the object
    file, so that it is available to the debugger. What I was
    thinking of was the options which cause the compiler to generate
    additional debugging checks in the library:

    -D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG -
    D_GLIBCXX_DEBUG_PEDANTIC

    (In practice, you should always use -ggdb too. I almost never
    use a debugger, but you can be sure that the one time I forget
    the -ggdb will be the one time I will want to use it.)

    > > Using a break to leave a loop is NEVER a good choice.


    > and i am the one who always believed that "break" was
    > especially created for the purpose of "breaking out of loop".


    "break" was created in C. So was "goto". That doesn't make
    them "good practice". In general, you should enter a loop at
    the top, and leave it at the bottom. In good code, about the
    only place you'll see a break is to terminate a case in a
    switch. (And I know, that's an over-generalization. There are
    cases where using a break is probably preferable to the
    alternatives, although I can't recall seeing any for the longest
    time. An experienced, professional programmer will recognize
    them, and be able to justify them. But since you're still
    learning, it's better to stick with the simple, absolute rule
    for the moment.)

    > > There's a very nice solution with a while loop:


    > > while ( iter != ivec.end() ) {
    > > {
    > > int first = *iter ++ ;
    > > if ( iter != ivec.end() ) {
    > > int second = *iter ++ ;
    > > std::cout << first + second << std::endl ;
    > > } else {
    > > std::cout << "odd number of elements, last was: "
    > > << first << std::endl ;
    > > }
    > > }
    > > }
    > > I'm not overly enthusiastic about spreading the increments out all over
    > > the loop, but it seems preferable here to the alternatives. It also
    > > avoids the requirement for a random access iterator, so you can replace
    > > vector with just about any container. (I still rather prefer the idea
    > > of using a container of std::pair, however, and handling the odd case at
    > > the end of input.)


    > James, that is really nice solution, i just loved it :). i always thought
    > that "for" loop is the official loop of C++ (like 'C' is the official
    > language of GNU, at least to speak) but i see, in this situation "while"
    > fits much better.


    The "for" loop has the advantage of bringing all of the loop
    control up to the top, where it is readily visible. In this
    case, of course, it doesn't work because increments are spread
    out all over the place. Which isn't ideal, but off hand, I
    can't find anything better. The most general form of a loop is
    while. If the resulting while is easily translated into a for,
    then you can consider it---I tend to use for in every case where
    the generic while has the proper form, but opinions about the
    exact cases differ slightly in practice. The important thing is
    to use for in the obvious cases, corresponding to those where it
    would be the proper idiom in another language, and to not use it
    when it would require forcing or restructuring the loop. For
    the in between cases (and they are legion), find a rule that
    you're comfortable with, and be consistent. And be ready to
    modify that rule if the company you work for has a different
    rule:).

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jul 20, 2007
    #11
  12. On Jul 20, 9:21 am, Andre Kostur <> wrote:
    > arnuld <> wrote in news:pan.2007.07.20.09.46.53.778891
    > @gmail.com:
    >
    > >> On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:
    > >> Using a break to leave a loop is NEVER a good choice.

    >
    > > and i am the one who always believed that "break" was especially created
    > > for the purpose of "breaking out of loop".

    >
    > For that, and switch statements. However it is a tool that is easily
    > misused. By using break you are stepping outside of the expected code
    > flow. Much like scattering goto's all over your code too. I'm not sure
    > that "never" is a good word, but it should probably be avoided where
    > possible.


    break and continue statements are like my bread and butter. I've
    personally never read any literature suggesting that break and goto
    are even in the same category in terms of their tendency to produce
    spaghetti code. To me, the number one factor affecting readability of
    code is the number of levels of indentation. Sticking to a "no breaks
    and no continues" policy is in direct conflict with my own philsophy
    of keeping the indentation level to a minimum. For the record, I
    learned C++ before C.

    A slightly unrelated but very similar topic I've always wondered about
    is the "one return point" philsophy. I'd rather hear fingernails
    scratching against a chalkboard for the rest of my life than see code
    like this:

    bool func(int param)
    {
    bool val = false;
    if (param < 5)
    {
    val = true;
    }
    else
    {
    val = false;
    //Lots of code here
    }

    return val;
    }

    when the following is at least an order of magnitude easier to
    maintain and read

    bool func(int param)
    {
    if (param < 5)
    return true;

    //Lots of code here
    return false;
    }

    especially if the "lots of code here" involves another if statement, a
    loop, switch statement, or some other indented scope.

    What are other people's thoughts on one return? It seems like people
    advocate for one return more often than not, but it's one of my worst
    pet peeves in all of C++.
    Zachary Turner, Jul 20, 2007
    #12
  13. Zachary Turner wrote:
    > On Jul 20, 9:21 am, Andre Kostur <> wrote:
    >> arnuld <> wrote in
    >> news:pan.2007.07.20.09.46.53.778891 @gmail.com:
    >>
    >>>> On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:
    >>>> Using a break to leave a loop is NEVER a good choice.

    >>
    >>> and i am the one who always believed that "break" was especially
    >>> created for the purpose of "breaking out of loop".

    >>
    >> For that, and switch statements. However it is a tool that is easily
    >> misused. By using break you are stepping outside of the expected
    >> code flow. Much like scattering goto's all over your code too. I'm
    >> not sure that "never" is a good word, but it should probably be
    >> avoided where possible.

    >
    > break and continue statements are like my bread and butter. I've
    > personally never read any literature suggesting that break and goto
    > are even in the same category in terms of their tendency to produce
    > spaghetti code. To me, the number one factor affecting readability of
    > code is the number of levels of indentation. Sticking to a "no breaks
    > and no continues" policy is in direct conflict with my own philsophy
    > of keeping the indentation level to a minimum. For the record, I
    > learned C++ before C.
    >
    > A slightly unrelated but very similar topic I've always wondered about
    > is the "one return point" philsophy. I'd rather hear fingernails
    > scratching against a chalkboard for the rest of my life than see code
    > like this:
    >
    > bool func(int param)
    > {
    > bool val = false;
    > if (param < 5)
    > {
    > val = true;
    > }
    > else
    > {
    > val = false;
    > //Lots of code here
    > }
    >
    > return val;
    > }
    >
    > when the following is at least an order of magnitude easier to
    > maintain and read
    >
    > bool func(int param)
    > {
    > if (param < 5)
    > return true;
    >
    > //Lots of code here
    > return false;
    > }
    >
    > especially if the "lots of code here" involves another if statement, a
    > loop, switch statement, or some other indented scope.
    >
    > What are other people's thoughts on one return? It seems like people
    > advocate for one return more often than not, but it's one of my worst
    > pet peeves in all of C++.


    It used to be important because just before the 'return' is when you
    deallocate all the locally allocated resources and so on. With RAII
    concept (and the symmetrical RDID (resource disposal is destruction),
    it's not that important any longer, since the destructors for all
    local objects are called upon exit no matter how many places cause
    that exit.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jul 20, 2007
    #13
  14. arnuld

    Bo Persson Guest

    Zachary Turner wrote:
    :: On Jul 20, 9:21 am, Andre Kostur <> wrote:
    ::: arnuld <> wrote in
    ::: news:pan.2007.07.20.09.46.53.778891 @gmail.com:
    :::
    ::::: On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:
    ::::: Using a break to leave a loop is NEVER a good choice.
    :::
    :::: and i am the one who always believed that "break" was especially
    :::: created for the purpose of "breaking out of loop".
    :::
    ::: For that, and switch statements. However it is a tool that is
    ::: easily misused. By using break you are stepping outside of the
    ::: expected code flow. Much like scattering goto's all over your
    ::: code too. I'm not sure that "never" is a good word, but it
    ::: should probably be avoided where possible.
    ::
    :: break and continue statements are like my bread and butter. I've
    :: personally never read any literature suggesting that break and goto
    :: are even in the same category in terms of their tendency to produce
    :: spaghetti code.

    Using goto is definitely worse. I think James' problem with breaking
    out of a for or while loop is that the break in the middle makes the
    initial statement false. You don't loop as long as you initially said,
    but sometimes change your mind halfway through. Not good!

    I might use a break sometimes, when the terminating condition isn't
    available at either end of the loop, like in:

    while(true)
    {
    // some inital sequence

    if (particular_condition)
    break;

    // some more code (that might remove the condition)

    }

    Here the while(true) is such an obvious lie, that the reader should
    expect another condition later.

    :: To me, the number one factor affecting
    :: readability of code is the number of levels of indentation.

    True.

    :: Sticking to a "no breaks and no continues" policy is in direct
    :: conflict with my own philsophy of keeping the indentation level to
    :: a minimum. For the record, I learned C++ before C.

    So, use it when it is good. :)

    ::
    :: A slightly unrelated but very similar topic I've always wondered
    :: about is the "one return point" philsophy. I'd rather hear
    :: fingernails scratching against a chalkboard for the rest of my
    :: life than see code like this:
    ::
    :: bool func(int param)
    :: {
    :: bool val = false;
    :: if (param < 5)
    :: {
    :: val = true;
    :: }
    :: else
    :: {
    :: val = false;
    :: //Lots of code here
    :: }
    ::
    :: return val;
    :: }
    ::
    :: when the following is at least an order of magnitude easier to
    :: maintain and read
    ::
    :: bool func(int param)
    :: {
    :: if (param < 5)
    :: return true;
    ::
    :: //Lots of code here
    :: return false;
    :: }
    ::

    I think this is acceptable, especially if there are several special
    param values that can be easily taken care of early.

    But this is somewhat religious, so others will disagree, for sure.



    Bo Persson
    Bo Persson, Jul 20, 2007
    #14
  15. arnuld

    Andre Kostur Guest

    Zachary Turner <> wrote in
    news::

    > On Jul 20, 9:21 am, Andre Kostur <> wrote:
    >> arnuld <> wrote in
    >> news:pan.2007.07.20.09.46.53.778891 @gmail.com:
    >>
    >> >> On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:
    >> >> Using a break to leave a loop is NEVER a good choice.

    >>
    >> > and i am the one who always believed that "break" was especially
    >> > created for the purpose of "breaking out of loop".

    >>
    >> For that, and switch statements. However it is a tool that is easily
    >> misused. By using break you are stepping outside of the expected
    >> code flow. Much like scattering goto's all over your code too. I'm
    >> not sure that "never" is a good word, but it should probably be
    >> avoided where possible.

    >
    > break and continue statements are like my bread and butter. I've
    > personally never read any literature suggesting that break and goto
    > are even in the same category in terms of their tendency to produce
    > spaghetti code. To me, the number one factor affecting readability of
    > code is the number of levels of indentation. Sticking to a "no breaks
    > and no continues" policy is in direct conflict with my own philsophy
    > of keeping the indentation level to a minimum. For the record, I
    > learned C++ before C.


    goto is far worse than break, but both (as well as continue) breaks the
    "natural" flow of the code.

    As for the number of levels of indentation, that may suggest that your
    functions are trying to do too many things (see Refactoring). But we're
    digressing further from concrete data into personal preferences....


    > A slightly unrelated but very similar topic I've always wondered about
    > is the "one return point" philsophy. I'd rather hear fingernails
    > scratching against a chalkboard for the rest of my life than see code
    > like this:
    >
    > bool func(int param)
    > {
    > bool val = false;
    > if (param < 5)
    > {
    > val = true;
    > }
    > else
    > {
    > val = false;
    > //Lots of code here
    > }
    >
    > return val;
    > }
    >
    > when the following is at least an order of magnitude easier to
    > maintain and read
    >
    > bool func(int param)
    > {
    > if (param < 5)
    > return true;
    >
    > //Lots of code here
    > return false;
    > }


    <implementation-specific, I think>
    Doesn't this style prevent the Return Value Optimization from occuring?
    I thought a bunch of the compilers needed a single return value to make
    RVO work. (OK, not a big deal with bool... but consider larger classes)
    </implementation-specific>

    <nitpick>
    For this specific example:

    bool func(int param)
    {
    bool val = true;

    if (param >= 5)
    {
    val = false;
    // Other code
    }

    return val;
    }
    </nitpick>

    > especially if the "lots of code here" involves another if statement, a
    > loop, switch statement, or some other indented scope.
    >
    > What are other people's thoughts on one return? It seems like people
    > advocate for one return more often than not, but it's one of my worst
    > pet peeves in all of C++.


    It's a little more important in the procedural world as there are no
    destructors to take care of things for you. So if you go an add another
    return into the middle of a function somewhere, you have to go find all
    of your resources and variables that are applicable at that point in the
    function to determine whether they need to be disposed of or not. In
    C++ we have destructors to take care of that work for you. So it's less
    of a problem.
    Andre Kostur, Jul 20, 2007
    #15
  16. arnuld

    James Kanze Guest

    On Jul 20, 10:22 pm, Zachary Turner <> wrote:
    > On Jul 20, 9:21 am, Andre Kostur <> wrote:


    [...]
    > > For that, and switch statements. However it is a tool that is easily
    > > misused. By using break you are stepping outside of the expected code
    > > flow. Much like scattering goto's all over your code too. I'm not sure
    > > that "never" is a good word, but it should probably be avoided where
    > > possible.


    > break and continue statements are like my bread and butter.


    You're not alone. A lot of programmers don't care about the
    quality of their code, whether it can be read and maintained,
    and even if it is correct.

    > I've
    > personally never read any literature suggesting that break and goto
    > are even in the same category in terms of their tendency to produce
    > spaghetti code.


    You've never read Dijkstra? Or Hoare?

    > To me, the number one factor affecting readability of
    > code is the number of levels of indentation. Sticking to a "no breaks
    > and no continues" policy is in direct conflict with my own philsophy
    > of keeping the indentation level to a minimum. For the record, I
    > learned C++ before C.


    Indentation levels aren't the problem in themselves, the problem
    is complexity. And break and continue add to it without adding
    indentation.

    Not using them results in simpler code. If it also results in
    too much indentation, then the problem isn't not using them; the
    problem is that you're doing too much in a single function to
    begin with. And using break or continue won't solve that
    problem.

    > A slightly unrelated but very similar topic I've always wondered about
    > is the "one return point" philsophy.


    It's necessary (but not sufficient) if you want to reason about
    code correctness. If you don't care whether the code is correct
    or not, you can ignore it. Otherwise, you can't.

    > I'd rather hear fingernails
    > scratching against a chalkboard for the rest of my life than see code
    > like this:


    > bool func(int param)
    > {
    > bool val = false;
    > if (param < 5)
    > {
    > val = true;
    > }
    > else
    > {
    > val = false;
    > //Lots of code here
    > }


    > return val;
    > }


    > when the following is at least an order of magnitude easier to
    > maintain and read
    >
    > bool func(int param)
    > {
    > if (param < 5)
    > return true;
    >
    > //Lots of code here
    > return false;
    > }


    Hmmm. Neither would pass code review most of the places I've
    worked. (Although many people who otherwise insist on a single
    return will accept checking of preconditions, with returns of an
    error status, at the top of the function.) The usual way to
    write something like this is:

    bool
    func( param )
    {
    bool result = param < 5 ;
    if ( ! result ) {
    callSomeFunction() ;
    }
    return result ;
    }

    > especially if the "lots of code here" involves another if statement, a
    > loop, switch statement, or some other indented scope.


    If you're nesting control constructs, you're functions are too
    big. (There are doubtlessly a few exceptions, but in general,
    it's the case.)

    > What are other people's thoughts on one return?


    Required for reliably correct code, although (as with every
    rule), there may be exceptions in special cases.

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jul 22, 2007
    #16
  17. arnuld

    James Kanze Guest

    On Jul 20, 10:59 pm, "Bo Persson" <> wrote:
    > Zachary Turner wrote:


    > :: On Jul 20, 9:21 am, Andre Kostur <> wrote:
    > ::: arnuld <> wrote in
    > ::: news:pan.2007.07.20.09.46.53.778891 @gmail.com:


    > ::::: On Fri, 20 Jul 2007 08:22:32 +0000, James Kanze wrote:
    > ::::: Using a break to leave a loop is NEVER a good choice.


    > :::: and i am the one who always believed that "break" was especially
    > :::: created for the purpose of "breaking out of loop".


    > ::: For that, and switch statements. However it is a tool that is
    > ::: easily misused. By using break you are stepping outside of the
    > ::: expected code flow. Much like scattering goto's all over your
    > ::: code too. I'm not sure that "never" is a good word, but it
    > ::: should probably be avoided where possible.


    > :: break and continue statements are like my bread and butter. I've
    > :: personally never read any literature suggesting that break and goto
    > :: are even in the same category in terms of their tendency to produce
    > :: spaghetti code.


    > Using goto is definitely worse.


    It depends. Using goto any old way is definitely worse, but
    what about a goto to break out of nested loops. (I've heard
    that one defended many times. After all, if you accept breaking
    out of a single loop, why not breaking out of nested loops?)

    Some people prefer "clever" code to correct code.

    > I think James' problem with breaking
    > out of a for or while loop is that the break in the middle makes the
    > initial statement false.


    Partially. The real problem is that you've increased the
    cyclometric complexity, and hidden the fact.

    There are, in a certain sense, two somewhat distinct problems
    involved. The first is that a loop should have a single entry
    and a single exit point. Anything else increases the
    cyclometric complexity, and makes the code considerably more
    difficult to understand and to maintain. From this point of
    view, however, something along the lines of:

    for ( ;; ) {
    // some code...
    if ( someCondition )
    break ;
    // more code...
    }

    does not cause a problem; it's just a straightforward
    implementation of the loop and a half problem. The second
    aspect is simply readability in the language you are using. C++
    has constructs (while, for) for checking the condition at the
    top of the loop, and one (do...while) for checking it at the
    bottom, but nothing readable for checking it in the middle. In
    specific shops, it's possible to define a convention which would
    make things readable---to begin with, the if above is clearly
    part of the loop control, and so should be indented to align
    with the for, and not with the controled code. (Try to get your
    automatic indention to respect that:).) But anything you agree
    on there is specific to the shop, and can't be portably counted
    on.

    > You don't loop as long as you initially said,
    > but sometimes change your mind halfway through. Not good!


    Worse: you said you'be loop as long as e.g. "x < 5", but you
    don't. You said that a guaranteed post-condition of the loop
    was "x >= 5", but it isn't.

    That's really the fundamental problem with the loop and a half
    idiom I suggested above: you promess that the loop will never
    terminate (barring catastropic failure), but it does.

    > I might use a break sometimes, when the terminating condition isn't
    > available at either end of the loop, like in:


    > while(true)
    > {
    > // some inital sequence
    > if (particular_condition)
    > break;
    > // some more code (that might remove the condition)
    > }


    > Here the while(true) is such an obvious lie, that the reader
    > should expect another condition later.


    Context dependent:). The code I write often does contain
    endless loops. (The software runs 24 hours a day, 7 days a
    week.)

    > :: To me, the number one factor affecting
    > :: readability of code is the number of levels of indentation.


    > True.


    Not exactly as stated. If it were literally true, just don't
    indent. I'm sure that that's not what the poster meant, but
    what did he mean, in fact. Increasing cyclometric complexity
    never improves readability, and break and continue do introduce
    additional control flows, and so increase cyclometric
    complexity.

    [Concerning multiple returns...]
    > I think this is acceptable, especially if there are several special
    > param values that can be easily taken care of early.


    The problem is estabilishing the rules when it would be
    acceptable. I DO have code with multiple returns: if the entire
    function body is a switch, for example, I'll occasionally use a
    return at the end of each case (rather than break). But it's
    difficult (for me at least) to formulate any reasonable rule;
    something along the lines: only in a top level control
    structure, and then only if all alternative paths terminate with
    a return? For the moment, I just consider the switch case a
    special case, and let it go at that. (Switches are special
    cases with regards to cyclometric complexity anyway.)

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jul 22, 2007
    #17
  18. arnuld

    Jerry Coffin Guest

    In article <>,
    says...

    [ ... ]

    > #include <iostream>
    > #include <vector>
    >
    > int main()
    > {
    > std::vector<int> ivec; /* empty vector */ int v_num;
    >
    > std::cout << "Please enter some numbers: " << std::endl; while(std::cin
    > >> v_num)

    > ivec.push_back(v_num);


    Even though it's minutely longer, I'd use an algorithm for this:

    std::copy(std::istream_iterator<int>(cin),
    std::istream_iterator<int>(),
    std::back_inserter(ivec));

    Since you're ultimately dealing with the integers in pairs, it might
    also be worth considering having a vector of pairs of integers, and put
    them into the pairs as you read them. This is likely to make the reading
    a little more complex, in the hope of making later manipulation a bit
    simpler and (possibly) reflecting the intent a bit more closely.

    If you decide to put the ints into pairs, you can cheat a little bit and
    set the last one to a pair of the number that was entered along with a
    zero in the second item of the pair. This allows you to treat all the
    items uniformly from that point onward. Under the circumstances, it may
    be more work than is worthwhile, but when you start to deal with more
    complex code, the basic concept can be extremely useful.

    Creating a vector of pairs could be done something like this:

    std::vector<std::pair<int, int> > pairs;

    for (int i=0; i<ivec.size()/2; i++)
    pairs.push_back(std::make_pair(ivec[i*2], ivec[i*2+1]);
    if (ivec.size() %2 != 0)
    pairs.push_back(std::make_pair(*ivec.rbegin(), 0);

    > if((ivec.size() % 2) != 0)
    > {
    > std::cout << "oops!, you enetered an odd number of numbers" <<
    > std::endl;
    > }


    If you're going to leave it as a vector of integers (instead of pairs)
    I'd consider removing the last one from the vector at this point, so as
    you sum the pairs, you don't have to deal with the possibility of an odd
    number of items in the vector.

    > for(std::vector<int>::const_iterator iter = ivec.begin(); iter !=
    > ivec.end(); iter += 2)
    > {
    > if((iter + 1) == ivec.end())
    > {
    > std::cout << *iter << std::endl;
    > }
    > else
    > {
    > std::cout << *iter + *(iter + 1) << std::endl;
    > }
    > }


    I prefer to keep the loop clean. The first leg of your if statement can
    only ever execute once, just before the loop terminates. In a case like
    that, I prefer to deal with that possibility outside the loop, perhaps
    something like this:

    // N/2 will truncate if N is odd
    for (int i=0; i<ivec.size()/2; i++)
    std::cout << ivec[i*2] + ivec[i*2+1] << "\n";

    // if we had an odd number of elements, print the last one.
    if (ivec.size() %2 != 0)
    std::cout << *ivec.rbegin();

    If you created the vector of pairs, printing out the sums could look
    something like this:

    struct sum {
    int operator()(std::pair<int, int> p) {
    return p.first + p.second;
    }
    };

    int main() {

    // ... code to read data and put into pairs goes here.

    // create and print out the sums of the pairs:
    std::transform(pairs.begin(), pairs.end(),
    std::eek:stream_iterator<int>(std::cout, "\n"),
    sum());

    return 0;
    }

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Jul 23, 2007
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Richard

    SSL / authentication primer

    Richard, Jul 25, 2003, in forum: Java
    Replies:
    2
    Views:
    474
    Richard
    Jul 25, 2003
  2. arnuld

    exercise 3.9, C++ Primer 4/e

    arnuld, Oct 9, 2006, in forum: C++
    Replies:
    2
    Views:
    281
    arnuld
    Oct 9, 2006
  3. arnuld
    Replies:
    14
    Views:
    853
    Zachary Turner
    Jul 13, 2007
  4. Kveldulv
    Replies:
    2
    Views:
    388
    cront
    Oct 20, 2007
  5. Replies:
    0
    Views:
    584
Loading...

Share This Page