Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Undefined behaviour or broken compiler?

Reply
Thread Tools

Undefined behaviour or broken compiler?

 
 
duckfreezone@gmail.com
Guest
Posts: n/a
 
      08-26-2005
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;
}

 
Reply With Quote
 
 
 
 
Alipha
Guest
Posts: n/a
 
      08-26-2005

http://www.velocityreviews.com/forums/(E-Mail Removed) 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;
> }


 
Reply With Quote
 
 
 
 
Clark S. Cox III
Guest
Posts: n/a
 
      08-26-2005
On 2005-08-25 23:13:10 -0400, (E-Mail Removed) 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
(E-Mail Removed)

 
Reply With Quote
 
annamalai.gurusami@gmail.com
Guest
Posts: n/a
 
      08-26-2005
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

 
Reply With Quote
 
msalters
Guest
Posts: n/a
 
      08-26-2005

(E-Mail Removed) 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

 
Reply With Quote
 
annamalai.gurusami@gmail.com
Guest
Posts: n/a
 
      08-26-2005
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

 
Reply With Quote
 
Andre Kostur
Guest
Posts: n/a
 
      08-26-2005
(E-Mail Removed) 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.
 
Reply With Quote
 
duckfreezone@gmail.com
Guest
Posts: n/a
 
      08-27-2005
Many thanks to all of those who replied; the information was exactly
what I was looking for. I'll now return to lurking

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Why are "broken iterators" broken? Steven D'Aprano Python 8 09-28-2008 09:19 PM
Re: Why are "broken iterators" broken? Fredrik Lundh Python 0 09-22-2008 04:32 PM
Re: Why are "broken iterators" broken? Cameron Simpson Python 0 09-22-2008 04:32 AM
undefined vs. undefined (was: new Array() vs []) VK Javascript 45 09-12-2006 05:26 PM
undefined behavior or not undefined behavior? That is the question Mantorok Redgormor C Programming 70 02-17-2004 02:46 PM



Advertisments