1

After researching a bit I don't understand the output (source code below):

42

42

45

I'm fine with the second, but why I get this output? It's coming from fooling around with avoiding global constants and variables in a bigger project. Could someone please explain it to me?

#include <iostream>

class Const
{
public:
    Const() = delete;
    static auto foo(int val = 42) -> int&;
};

auto Const::foo(int val) -> int&
{
    static int sval = val;
    return sval;
}

int main()
{
    std::cout << Const::foo() << std::endl;
    Const::foo(24);
    std::cout << Const::foo() << std::endl;
    Const::foo() = 45;
    std::cout << Const::foo() << std::endl;

    return 0;
}
macnet65
  • 33
  • 5
  • Actually I'm surprised it's not `42` all three times. I suppose the initialization is only done once, so `foo(24)` and subsequent calls of `foo()` don't change the value, but because it returns a reference `Const::foo() = 45` _does_ change it? – Nathan Pierson Nov 12 '20 at 17:07
  • @NathanPierson Function returns reference, and this reference is being assigned `45` before 3rd print. – Yksisarvinen Nov 12 '20 at 17:09
  • @Yksisarvinen I'm not surprised that `Const::foo() = 45;` changes the value of `sval`. I'm surprised that `Const::foo(24)` (and, similarly, the final call to `Const::foo()`) don't. – Nathan Pierson Nov 12 '20 at 17:10
  • 2
    @NathanPierson Well, you are correct. Initialization is only done once and the line with assignment is skipped on all subsequent calls to `Const::foo()`. if there was another `sval = val;` before `return`, `Const::foo(24)` could change the result, but otherwise it's only changeable via the returned reference and parameter is ignored. – Yksisarvinen Nov 12 '20 at 17:17
  • Related: https://stackoverflow.com/q/5567529/5754656 – Artyer Nov 12 '20 at 21:36

1 Answers1

1

In your code:

#include <iostream>

class Const   // what a strange name for something that is not const.
{
public:
    Const() = delete;
    static auto foo(int val = 42) -> int&; 
};

auto Const::foo(int val) -> int&   // if you don't return a const reference, 
                                   // it may be modified by the caller 
{
    static int sval = val;   // val is not const, and only initialized 
                             // once.
    return sval;             // you return a reference to a mutable value.
}

int main()
{
    std::cout << Const::foo() << std::endl;    
    Const::foo(24);  // this changes nothing, the static  variable sval
                     // has already been initialized.  
    std::cout << Const::foo() << std::endl;
    Const::foo() = 45;                         // the reference returned by foo() is 
                                               // not const.  SO that works.
    std::cout << Const::foo() << std::endl;

    return 0;
}

To fix, Const::foo() should return a const int&.

Forget about using static function variables. When entering the function, the code must check each time if its static variables have been initialized. This usually involves using a hardware fence or some other thread-safe mechanism. These will unnecessarily slow down execution, especially when accessing these const values from multiple threads.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19