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;
}
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? Commented Nov 12, 2020 at 17:07
  • @NathanPierson Function returns reference, and this reference is being assigned 45 before 3rd print. Commented Nov 12, 2020 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. Commented Nov 12, 2020 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. Commented Nov 12, 2020 at 17:17
  • Related: stackoverflow.com/q/5567529/5754656 Commented Nov 12, 2020 at 21:36

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.