Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return value optimization in Visual Studio 2015?

In a probject I used code similar to the following:

class C {
public:
    C() {}

    C(const C&) = delete;
};

C f() {
    return C();
}

int main() {
    f();
}

In every previous Visual C++ compiler I used (up to 2013), that has never been a problem. But when I try to compile it with the new Visual C++ 2015 compiler I get the following error:

1>c:\devel\c++11\playground\main.cpp(10): error C2280: 'C::C(const C &)': attempting to reference a deleted function
1>  c:\devel\c++11\playground\main.cpp(6): note: see declaration of 'C::C'

I'm not sure why it previously worked but I assume that because of return value optimization the default constructor was called and not the copy constructor.

Is the code I used even legal C++? And if not, what would be the correct way of implementing this code without requiring a copy constructor for my class C? I could of course use a move constructor but then I assume the code would have never been valid C++ before C++11?

like image 769
fschoenm Avatar asked Jul 21 '15 12:07

fschoenm


People also ask

What is return function in optimization?

In the context of the C++ programming language, return value optimization (RVO) is a compiler optimization that involves eliminating the temporary object created to hold a function's return value. RVO is allowed to change the observable behaviour of the resulting program by the C++ standard.

How does RVO work?

RVO is a compiler technique to avoid copying objects when the object is returned as function value. This optimization helps a function to efficiently return large objects while also simplifying the function's interface and eliminating scope for errors.

Is return value optimization guaranteed?

Compilers often perform Named Return Value Optimization (NRVO) in such cases, but it is not guaranteed.

Does C have return value optimization?

> Note also that C doesn't have return-value-optimization, hence all your struct-returning functions will cause a call to memcpy (won't happen when compiled in C++ mode of course).


2 Answers

Function arguments and return values are initialized using copy-initialization. Copy-initialization requires copy constructors to be accessible, even if they are elided by (N)RVO:

If T is a class type, and the type of other is different, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used.

like image 93
Maxim Egorushkin Avatar answered Oct 18 '22 07:10

Maxim Egorushkin


You need to follow the rule of 5. Since you deleted the copy constructor, you need to define your move constructor.

C(C&&) = default;
C& operator=(C&&) = default;

With move constructor - works
Without move constructor - doesn't work, violates rule of 5

Note the above site uses gcc and even it will not compile, so it is not specific to Visual Studio, this is a defined and expected behavior.

like image 20
Cory Kramer Avatar answered Oct 18 '22 09:10

Cory Kramer