Undefined behaviour or broken compiler?

Discussion in 'C++' started by duckfreezone@gmail.com, Aug 26, 2005.

  1. Guest

    Hi,

    I've got a small test program which behaves correctly (IMHO) on all
    compilers that I have acccess to, with the exception of the gcc on
    Macintosh OSX "gcc version 4.0.0 (Apple Computer, Inc. build 5026)"

    Looks to be that the order of evaluation of the assignment on OSX is
    different to other systems. I *think* it is wrong on OSX, or am I
    simply relying on undefined behaviour?

    On a "correct" system, I get this output:
    before:
    0 members
    after:
    0 : 'something'='something extra'
    1 members

    On OSX, I get this output:
    before:
    0 members
    after:
    0 : 'something'=''
    1 members

    I appreciate that this newsgroup doesn't cover platform-specific
    issues, but my question is more one of trying to understand if this
    program is relying on undefined behaviour.

    Source follows:

    #include <cstdlib>
    #include <iostream>
    #include <map>
    #include <string>

    static std::map<std::string,std::string> strings;

    static void dump (const std::string& prefix)
    {
    std::cout << prefix << ":" << std::endl;
    unsigned int count = 0;
    for (std::map<std::string,std::string>::const_iterator si =
    strings.begin (); si != strings.end (); ++si)
    {
    const std::string s1 (si -> first);
    const std::string s2 (si -> second);
    std::cout << " " << count++ << " : '" << s1 << "'='" << s2 << "'"
    << std::endl;
    }
    std::cout << count << " members" << std::endl;
    }


    static std::string findString (const std::string& which)
    {
    if (strings.find (which) != strings.end ()) return strings [which];
    return which + " extra";
    }


    int main (int argc, char *argv[])
    {
    const std::string key ("something");
    dump ("before");
    strings [key] = findString (key);
    dump ("after");
    return EXIT_SUCCESS;
    }
    , Aug 26, 2005
    #1
    1. Advertising

  2. Alipha Guest

    wrote:
    > Hi,
    >
    > I've got a small test program which behaves correctly (IMHO) on all
    > compilers that I have acccess to, with the exception of the gcc on
    > Macintosh OSX "gcc version 4.0.0 (Apple Computer, Inc. build 5026)"
    >
    > Looks to be that the order of evaluation of the assignment on OSX is
    > different to other systems. I *think* it is wrong on OSX, or am I
    > simply relying on undefined behaviour?
    >
    > On a "correct" system, I get this output:
    > before:
    > 0 members
    > after:
    > 0 : 'something'='something extra'
    > 1 members
    >
    > On OSX, I get this output:
    > before:
    > 0 members
    > after:
    > 0 : 'something'=''
    > 1 members


    Both are correct outputs. See below.

    >
    > I appreciate that this newsgroup doesn't cover platform-specific
    > issues, but my question is more one of trying to understand if this
    > program is relying on undefined behaviour.
    >
    > Source follows:
    >
    > #include <cstdlib>
    > #include <iostream>
    > #include <map>
    > #include <string>
    >
    > static std::map<std::string,std::string> strings;
    >
    > static void dump (const std::string& prefix)
    > {
    > std::cout << prefix << ":" << std::endl;
    > unsigned int count = 0;
    > for (std::map<std::string,std::string>::const_iterator si =
    > strings.begin (); si != strings.end (); ++si)
    > {
    > const std::string s1 (si -> first);
    > const std::string s2 (si -> second);
    > std::cout << " " << count++ << " : '" << s1 << "'='" << s2 << "'"
    > << std::endl;
    > }
    > std::cout << count << " members" << std::endl;
    > }
    >
    >
    > static std::string findString (const std::string& which)
    > {
    > if (strings.find (which) != strings.end ()) return strings [which];
    > return which + " extra";
    > }
    >
    >
    > int main (int argc, char *argv[])
    > {
    > const std::string key ("something");
    > dump ("before");
    > strings [key] = findString (key);


    Implementation specific behavior. strings[key] may be evaluated first
    before the function call, in which case string[key] is created and
    given the value "". See the link for more info:

    http://www.eskimo.com/~scs/C-faq/q3.4.html

    The correct way to write the above statement would be:

    std::string value = findString(key);
    strings[key] = value;

    > dump ("after");
    > return EXIT_SUCCESS;
    > }
    Alipha, Aug 26, 2005
    #2
    1. Advertising

  3. On 2005-08-25 23:13:10 -0400, said:

    > Hi,
    >
    > I've got a small test program which behaves correctly (IMHO) on all
    > compilers that I have acccess to, with the exception of the gcc on
    > Macintosh OSX "gcc version 4.0.0 (Apple Computer, Inc. build 5026)"
    >
    > Looks to be that the order of evaluation of the assignment on OSX is
    > different to other systems. I *think* it is wrong on OSX, or am I
    > simply relying on undefined behaviour?


    Neither is wrong, and it's not undefined behaviour.

    > On a "correct" system, I get this output:
    > before:
    > 0 members
    > after:
    > 0 : 'something'='something extra'
    > 1 members
    >
    > On OSX, I get this output:
    > before:
    > 0 members
    > after:
    > 0 : 'something'=''
    > 1 members
    >
    > I appreciate that this newsgroup doesn't cover platform-specific
    > issues, but my question is more one of trying to understand if this
    > program is relying on undefined behaviour.
    >
    > Source follows:
    >
    > #include <cstdlib>
    > #include <iostream>
    > #include <map>
    > #include <string>
    >
    > static std::map<std::string,std::string> strings;
    >
    > static void dump (const std::string& prefix)
    > {
    > std::cout << prefix << ":" << std::endl;
    > unsigned int count = 0;
    > for (std::map<std::string,std::string>::const_iterator si =
    > strings.begin (); si != strings.end (); ++si)
    > {
    > const std::string s1 (si -> first);
    > const std::string s2 (si -> second);
    > std::cout << " " << count++ << " : '" << s1 << "'='" << s2 << "'"
    > << std::endl;
    > }
    > std::cout << count << " members" << std::endl;
    > }
    >
    >
    > static std::string findString (const std::string& which)
    > {
    > if (strings.find (which) != strings.end ()) return strings [which];
    > return which + " extra";
    > }


    As a style issue, I'd write that as (avoids searching the map twice):

    static std::string findString (const std::string& which)
    {
    std::map<std::string,std::string>::const_iterator iter = strings.find(which);
    if (iter != strings.end ()) return *iter;
    return which + " extra";
    }

    >
    >
    > int main (int argc, char *argv[])
    > {
    > const std::string key ("something");
    > dump ("before");
    > strings [key] = findString (key);


    Either side of the '=' operator may be evaluated first, if the left
    side is evaluated first, then an empty string is inserted into the map
    with that key; that empty string is then found by findString, and
    returned.


    > dump ("after");
    > return EXIT_SUCCESS;
    > }



    --
    Clark S. Cox, III
    Clark S. Cox III, Aug 26, 2005
    #3
  4. Guest

    Alipha wrote:

    > Implementation specific behavior. strings[key] may be evaluated first
    > before the function call, in which case string[key] is created and
    > given the value "". See the link for more info:
    >
    > http://www.eskimo.com/~scs/C-faq/q3.4.html


    I am not sure whether this is true for assignment operators. If
    I write

    g() = f(); // g() returns an lvalue

    Both g() and f() has to be called and then the assignment happens.
    The above URL just says that both the following are correct.

    case 1:

    1. Evaluate g().
    2. Evaluate f();
    3. Carry out assignment.

    case 2:

    1. Evaluate f();
    2. Evaluate g();
    3. Carry out assignment.

    In both cases, the result of f() is assigned to result of g(). So
    the assignment should work fine.

    Did I miss anything?

    I tried the above piece of code with g++ 3.3.4 (on Slackware 10.0). The
    optimization changes the behaviour of the program.

    (begin-quote)

    $ g++ foo.cc
    $ ./a.out
    before:
    0 members
    after:
    0 : 'something'='something extra'
    1 members
    $ g++ -O foo.cc
    $ ./a.out
    before:
    0 members
    after:
    0 : 'something'=''
    1 members
    $

    (end-quote)

    Rgds,
    anna
    , Aug 26, 2005
    #4
  5. msalters Guest

    schreef:

    > Alipha wrote:
    >
    > > Implementation specific behavior. strings[key] may be evaluated first
    > > before the function call, in which case string[key] is created and
    > > given the value "". See the link for more info:
    > >
    > > http://www.eskimo.com/~scs/C-faq/q3.4.html

    >
    > I am not sure whether this is true for assignment operators. If
    > I write
    >
    > g() = f(); // g() returns an lvalue
    >
    > Both g() and f() has to be called and then the assignment happens.
    > The above URL just says that both the following are correct.
    >
    > case 1:
    >
    > 1. Evaluate g().
    > 2. Evaluate f();
    > 3. Carry out assignment.
    >
    > case 2:
    >
    > 1. Evaluate f();
    > 2. Evaluate g();
    > 3. Carry out assignment.
    >
    > In both cases, the result of f() is assigned to result of g(). So
    > the assignment should work fine.


    Fine, in the sense that it's not UB. However, assume the following:

    std::list<int> L;
    int& f() { L.push_back(1); return L.back(); }
    int& g() { L.push_back(2); return L.back(); }
    int main() { g() = f(); }

    Clearly, it matters whether g() is called before or after f().
    The assignment is legal in both cases, but L will differ.

    HTH,
    Michiel Salters
    msalters, Aug 26, 2005
    #5
  6. Guest

    msalters wrote:

    > Fine, in the sense that it's not UB. However, assume the following:


    UB?

    > std::list<int> L;
    > int& f() { L.push_back(1); return L.back(); }
    > int& g() { L.push_back(2); return L.back(); }
    > int main() { g() = f(); }
    >
    > Clearly, it matters whether g() is called before or after f().
    > The assignment is legal in both cases, but L will differ.


    Thanks for that good example. Now I understand.

    Rgds,
    anna
    , Aug 26, 2005
    #6
  7. Andre Kostur Guest

    wrote in news:1125067586.783128.141350
    @o13g2000cwo.googlegroups.com:

    > msalters wrote:
    >
    >> Fine, in the sense that it's not UB. However, assume the following:

    >
    > UB?


    Undefined Behaviour. Behaviours defined by the Standard as
    "compiler/implementation is free to do as it wishes, we make no guarantees
    about anything".

    As an example, attempting to call a method through a NULL pointer is
    Undefined Behaviour:

    Class * c = 0;

    c->fn();


    That call invokes UB because the NULL pointer is dereferenced. However, on
    many implementations this will result in everything working properly
    (assuming that fn() doesn't attempt to use any object member variables or
    virtual functions). However this behaviour isn't guaranteed on all
    platforms. It is perfectly acceptable (from a Standard point-of-view) for
    your program to immediately crash, or an exception may be thrown, or your
    hard drive may be formatted.
    Andre Kostur, Aug 26, 2005
    #7
  8. Guest

    Many thanks to all of those who replied; the information was exactly
    what I was looking for. I'll now return to lurking :)
    , Aug 27, 2005
    #8
    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. Mantorok Redgormor
    Replies:
    70
    Views:
    1,720
    Dan Pop
    Feb 17, 2004
  2. Steven D'Aprano

    Why are "broken iterators" broken?

    Steven D'Aprano, Sep 21, 2008, in forum: Python
    Replies:
    8
    Views:
    631
  3. Cameron Simpson

    Re: Why are "broken iterators" broken?

    Cameron Simpson, Sep 22, 2008, in forum: Python
    Replies:
    0
    Views:
    561
    Cameron Simpson
    Sep 22, 2008
  4. Fredrik Lundh

    Re: Why are "broken iterators" broken?

    Fredrik Lundh, Sep 22, 2008, in forum: Python
    Replies:
    0
    Views:
    584
    Fredrik Lundh
    Sep 22, 2008
  5. VK
    Replies:
    45
    Views:
    571
    Dr John Stockton
    Sep 12, 2006
Loading...

Share This Page