0

I am running into a problem which has thrown me for a loop (no pun intended). I was trying to illustrate how overloaded operators can enhance the readability of code quite a bit. In order to do so, I wrote a simple class called 'cow' (no special meaning). When I compile the code on a Mac, it compiles cleanly and executes as expected.

The exact same code compiled on a Linux box (Ubuntu) also compiles cleanly, but executed with an incorrect result.

Somewhere, I must be missing something obvious, but I'm not seeing it.

Here is the code:

#include <iostream>
#include <sstream>
using namespace std;

class cow {
public:
    cow();
    cow(int i);
    int add(int a);
    int add(string str);
    int get() const;
private:
    int i;
};

cow::cow() {
    i = 0;
}

cow::cow(int j) {
    i = j;
}

int cow::add(string str) {
    stringstream s;
    int num;
    s << str;
    s >> num;

    return i += num;
}

int cow::add(int a) {
    return i += a;
}

int cow::get() const {
    return i;
}

int main() {
    cow i(15);
    cout << i.get() << " : " << i.add(15) << " : " << i.add("-15.0");
    return 0;
}

Compiling (g++ -Wall -o cow cow.cpp) yields no warnings and no errors and creates an executable.

Executing the program on the Linux box yields:

$ ./cow
15 : 15 : 0

Executing the program on a Mac yields:

$ ./cow
15 : 30 : 15

The C++ compiler on the Mac is:

$ g++ --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.0.0 (clang-900.0.38)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

The C++ compiler on the Linux box is:

$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Any suggestions as to what is causing this behavior is appreciated, as are ways to fix it on the Linux box!

Thanks,

Kees

Kees Leune
  • 13
  • 1

2 Answers2

2

You're running into undefined behaviour in this line:

cout << i.get() << " : " << i.add(15) << " : " << i.add("-15.0");

It's up to the compiler which order it evaluates i.get (), i.add(15) and i.add("-15.0") - it's not normally a problem unless evaluating one of them would change the output of another of them (which is the case here - i changes).

As you're using different compilers (g++ on Linux, clang on Mac), each is evaluating in different orders.

Steve
  • 1,747
  • 10
  • 18
2

You're getting an undefined behavior because you change the state of the instance several times within one expression. By the C++ standard, your calls to i in this line:

 cout << i.get() << " : " << i.add(15) << " : " << i.add("-15.0");

could be performed in any order. It is just your luck the Mac's compiler performs the calls left to right as you expect. To get the reliable result you should evaluate those calls sequentially, like:

auto a1 = i.get();
auto a2 = i.add(15);
auto a3 = i.add("-15.0);
cout << a1 << " : " << a2 << " : " << a3;
Jurlie
  • 1,014
  • 10
  • 27
  • Thank you for your response. It also seems like I need to improve my search skills, since this was a duplicate question. Apologies. – Kees Leune Oct 31 '17 at 11:33
  • To be honest, I do not quite agree with the moderator who marked the question as a duplicate. Of course, the referenced article gives comprehensive explanation of the case, but the point is when someone just starts learning C++, they most probably don't know what term "Sequence point" means, or, because of the lack of experience they cannot realize the effect you've described is the sign of misunderstanding of the sequence points concept. – Jurlie Nov 01 '17 at 00:06