I was testing out the Return Value Optimizations in C++ Visual Studio 2022. I was surprised that the following program needed to call the copy constructor:
#include <iostream>
class A {
public:
    A() { std::cout << "Constructor calling" << std::endl; }
    A(A& a) { std::cout << "Copy Constructor calling" << std::endl; }
    A(const A& a) { std::cout << "const Copy Constructor calling" << std::endl; }
};
A& getA() { A a; return a; }
int main() {
    A a = getA();
    return 0;
}
This outputs Constructor Calling\nCopy Constructor Calling, which means it did not get optimized with NRVO. Yet when I change the program to the following (just removed the return by reference on getA()):
#include <iostream>
class A {
public:
    A() { std::cout << "Constructor calling" << std::endl; }
    A(A& a) { std::cout << "Copy Constructor calling" << std::endl; }
    A(const A& a) { std::cout << "const Copy Constructor calling" << std::endl; }
};
A getA() { A a; return a; }
int main() {
    A a = getA();
    return 0;
}
Now we get the output as just Constructor calling and no calls to the copy constructor. Why does it not get optimized when I am returning by reference?
