0
class Foo {
private:
    int num;
    std::string str;

public:
    Foo& operator=(const Foo& rhs) {
        this->num = rhs.num;
        this->str = rhs.str;
        return *this;
    }

    Foo& operator+(const Foo& rhs) {
        Foo tmp(this->num + rhs.num, this->str + rhs.str);
        return tmp;
    }
};

If I write a code like Foo f3; f3 = f1 + f2;, runtime error occurs when this->str = rhs.str; in operator=() is executed.

I think temporary std::string object(this->str + rhs.str) made in operator+() is regional so it is removed when the function call is finished. But int value(this->num + rhs.num) is passed well without problems.

Why is this difference happening?

EnDelt64
  • 1,270
  • 3
  • 24
  • 31
  • What is the runtime error you are getting? Did you debug the values? – RoQuOTriX May 04 '21 at 09:30
  • 1
    A "typical" operator+ will return Foo by value (without the &). Your code returns a reference to a temporary Foo. – André May 04 '21 at 09:31
  • 1
    You're returning a reference to a temporary. Don't do that. And take a look at the canonical forms of the [arithmetic operators](https://en.cppreference.com/w/cpp/language/operator_arithmetic) for guidance on the correct prototype. – Useless May 04 '21 at 09:31
  • There's a difference because you made `operator+()` return a reference, which (a) it shouldn't do and (b) **no** function should do if the reference is to a local variable. Just don't do that. It has undefined behaviour. – underscore_d May 04 '21 at 09:35
  • 1
    Oh, and you should really turn on all your compiler's warnings. – Useless May 04 '21 at 09:37
  • @RoQuOTriX I'm using Visual Studio 2019. – EnDelt64 May 05 '21 at 05:07

2 Answers2

1

Your operator+ returns a reference to the temporary Foo called tmp. It will be automatically destroyed after the return.

You don't show a minimal, compilable example. But most likely, the assignment afterwards to f3 then fails.

The idiomatic approach for an operator+ is to return Foo by value.

// Note the missing & in the Foo return value
Foo operator+( const Foo& rhs )
{  
    Foo result( this->num + rhs.num, this->str + rhs.str );
    return result;
}
André
  • 18,348
  • 6
  • 60
  • 74
1

You already correctly asserted that tmp is only local to Foo::operator+ and thus the returned reference is invalid (a dangling reference).

But int value(this->num + rhs.num) is passed well without problems.

I think you refer to code like this:

int operator+(const Foo& rhs) {
   int tmp(this->num + rhs.num);
   return tmp;
}

Yes, that works. Notice the important difference that int operator+(const Foo& rhs) returns a value. That is, you don't return a reference to tmp, but a copy of it.


That's why an idiomatic operator+ would return by value instead of by reference. You want:

// V no reference
Foo operator+(const Foo& rhs) { ... }

See also this great question about canonical operator overloading.

Lukas-T
  • 11,133
  • 3
  • 20
  • 30