user5406390
user5406390

Reputation: 13

gcc / c++11 : optimization level changes the result of an operation

In a C++ Class, I 've overloaded operator-(). When I compile with -O0, it behaves as expected but when I compile with at least -O1, the result of calling operator-() is wrong despite no error is generated.

I'm not a C++ guru but nothing seems weird to me in the code snippet below. Unlike other cases I encountered on this site, I have no inline asm, I'm not calling a library, etc. Everything is self contained in the code.

Here are the version of gcc I used :

g++ (GCC) 4.9.3
Copyright © 2015 Free Software Foundation, Inc.
Ce logiciel est libre; voir les sources pour les conditions de copie.
Il n'y a PAS GARANTIE; ni implicite pour le MARCHANDAGE ou pour un BUT PARTICULIER.

g++ (GCC) 5.2.0
Copyright © 2015 Free Software Foundation, Inc.
Ce logiciel est libre; voir les sources pour les conditions de copie.
Il n'y a PAS GARANTIE; ni implicite pour le MARCHANDAGE ou pour un BUT PARTICULIER.

Compilation commands :

OK : g++ --std=c++11 -O0 -o test test.cpp
KO : g++ --std=c++11 -O1 -o test test.cpp

I get the expected warning :

test.cpp: In member function ‘A& A::operator-(const A&)’:
test.cpp:23:5: attention : reference to local variable ‘tmp’ returned 
[-Wreturn-local-addr]
   A tmp(*this);
     ^

Adding -Wno-return-local-addr changes nothing since it's just removing the warning

Here is the code snippet which reproduces the problem :

#include <iostream>

using namespace std;

class A {
public:
  double val;

  A(int _val) : val(_val) {}

  A() : val(0.0) {}

  A(const A&) = default;
  A(A&&) = default;
  A& operator=(const A&) = default;
  A& operator=(A&&) = default;

  A& operator-(const A& other) {
    A tmp(*this);
    tmp.val -= other.val;

    return tmp;
  }

};

int main() {

  A a(3);
  A b(2);

  A c = b - a;

  cout << c.val << endl;

  return 0;
}

If I add an operator-=()

  A& operator-=(const A& other) {
    this->val -= other.val;

    return *this;
  }

and change in main :

A c = b - a;

with

A c(b);
c -= a;

I works perfectly whatever the -Ox option.

I suspect that returning a reference to a local variable from operator-() is the source of the problem (despite the RVO feature of c++11 ?). What I don't get is why the level of optimization has such an effect ?

After all, is there something wrong with mys code ?

Upvotes: 1

Views: 355

Answers (1)

Peter
Peter

Reputation: 36597

Your operator-() is returning a reference to a local variable. That causes the caller to exhibit undefined behaviour if it uses that reference.

Conventionally, operator-() returns an object by value, not by reference. This makes sense, as c = a - b typically leaves a and b unchanged, and gives c the difference (however that is defined) between them.

Upvotes: 3

Related Questions