c++cppcheck

Cppcheck says 'Reference to temporary returned' but code runs fine. False positive maybe?


Consider the following mwe, implementing a simple class that overloads the multiply operator:

#include <iostream>

using namespace std;

class A {
public:
  double a;
  
  A &operator*(double b)
  {
        a *= b;
        return *this;
  }
    
  friend A &operator*(double b, A &m) { return m * b; } // (*)
};

int main()
{
    
    A a;
    a.a = 5.0;
    a * 3.0;
    std::cout << a.a << std::endl;
    3.0 * a;
    std::cout << a.a << std::endl;
    return 0;
}

It compiles and runs just fine, printing the expected output. However cppcheck gives the following warning.

tmp.cpp:15:48: error: Reference to temporary returned. [returnTempReference]
friend A &operator*(double b, A &m) { return m * b; }

When rewriting (*) as

friend A &operator*(double b, A &m) { m * b; return m; }

The error from cppcheck disappears.

So, is this an actual problem and I'm overseeing something, or is it a false positive by cppcheck?

Some context: In my code, class A is actually a Matrix class, for which I don't want to create a new object upon multiplying with a constant, thus returning the reference.


Solution

  • Your code does not return a reference to a temporary. One is inclided to think that, because what you implemented as operator* is actually an operator*=. If you did implment operator* which does not modify the current A but returns a new one, then returning a reference would be problematic.

    I dont have the tool available, but I would expect it to not complain about:

    #include <iostream>
    
    using namespace std;
    
    class A {
    public:
      double a;
      
      A &operator*=(double b)
      {
            a *= b;
            return *this;
      }
        
      friend A &operator*=(double b, A &m) { return m *= b; } // (*)
    };
    
    int main()
    {
        
        A a;
        a.a = 5.0;
        a *= 3.0;
        std::cout << a.a << std::endl;
        3.0 *= a;
        std::cout << a.a << std::endl;
        return 0;
    }
    

    Which really does the same as your code, but with the expected semantics of *=.

    As songyuanyao mentions in a comment, it might be that the tool simply expects m*b to be a rvalue-expression, as it usually is, without actually checking the implementation of your *.