C++ RVO: when it happens? - c++

http://coliru.stacked-crooked.com/a/c795a5d2bb91ae32
#include <iostream>
struct X {
X(const char *) { std::cout << 1; }
X(const X &) { std::cout << 2; }
X(X &&) { std::cout << 3; }
};
X f(X a) {
return a;
}
X g(const char * b) {
X c(b);
return c;
}
int main() {
f("hello"); // 13
g("hello"); // 1
}
Is there any difference in the last line of function f(X a):
return a; instead of return std::move(a);?
Is it true that function f doesn't have RVO but g has NRVO?

Is there any difference in the last line of function f(X a): return a; instead of return std::move(a);?
No. a is a local variable of the function, so return a can move from it.
Is it true that function f doesn't have RVO but g has NRVO?
Correct. Named elision never applies to function parameters; it only applies to local variables that are not function parameters.

Related

Deduced type with 'auto &&' as function return type

In the following snippet, the function B::f() is a "wrapper" around the function A::f(). But I assume that A::f() return type is an "opaque" type which I don't know if it has a value or reference semantics. So I cannot use auto or const auto & as return type for B::f(). I thought that auto && would do the trick, but it does not as auto && is deduced as A::OpaqueType &... Is it possible here to avoid writing A::OpaqueType?
#include <iostream>
struct A {
using OpaqueType=int; // But it could have been `const int &`
OpaqueType f() const {
return i;
}
int i=42;
};
struct B {
// how could I use `auto` here to avoid writing the `A::OpaqueType`?
// I would have expected that `auto &&` would do the trick but it does not
A::OpaqueType f() const {
return a.f();
}
A a;
};
int main()
{
B b;
std::cout << b.f() << std::endl;
}
The following snippet confuses me, as I would have expected that the return type of f() and g() would be int, but it is int & for f() and int && for g() (I don't even understand why it is not the same)... How this can be explained?
#include <iostream>
auto &&f() {
int i=42;
return i;
}
struct A {
int f() {return i;}
int i=42;
};
auto &&g() {
A a;
return a.f();
}
int main()
{
if (std::is_same_v<decltype(f()), int &>) {
std::cout << "f() return type is 'int &'\n";
}
if (std::is_same_v<decltype(g()), int &&>) {
std::cout << "g() return type is 'int &&'\n";
}
}
Thanks!
Pretty sure what you are looking for is decltype(auto). This will return by value if the expression in the return statement returns by value, and it will return by reference if the expression in the return statement returns by reference. That would give you
decltype(auto) f() const {
return a.f();
}

What is the logic behind the "lvalueness" and "rvalueness" of a value returned by a function

In the following code I was expecting the function Foo f(Foo& x) to return an rvalue and to my surprise it doesn't. So I started testing some cases to find out the logic behind the "lvalueness" and "rvlaueness" of the returned value. It turns out that returning a named variable of type class is an lvalue. Perhaps I'm missing something
#include <iostream>
class Foo
{
int val;
public:
Foo(int value=10)
{
val = value;
};
Foo(Foo& other)
{
std::cout << "copy ctor used" << std::endl;
val = other.val;
};
Foo(Foo&&)
{
std::cout << "move ctor used" << std::endl;
};
Foo operator=(Foo& other)
{
std::cout << "copy assign used" << std::endl;
val = other.val;
return *this;
}
Foo operator=(Foo&& a)
{
std::cout << "move assign used" << std::endl;
return *this;
}
void set(int value) { val = value; };
int get() { return val; };
};
int z = 20;;
int case1()
{
return z;
};
int case2(int x)
{
return x;
};
Foo case3(Foo x)
{
return x;
};
Foo case4(Foo& x)
{
return x;
};
Foo y;
Foo case5()
{
return y;
}
Foo& case6(Foo& x)
{
return x;
};
Foo case7()
{
Foo x;
return x;
}
int main()
{
/*case1() = 50;*/ // as expected: not OK the return value is not an lvalue
int c = 40;
/*case2(c) = 50; */ // as expected: not OK the return value is not an lvalue
Foo a;
Foo b = 30;
case3(a) = b; // OK: not at all expected the return value is an lvalue
// I don't see the difference with case 2
//copy construction of the argument and return value
//copy assigning of b
case4(a) = b; //OK: behaving exactly like case 3 except for the copy construction
// of the argument and the return value
// copy assigning taking place as expected
case5() = b; // same as case 3
case6(a) = b; //just copy assigning taking place
// the same reference to a is returned
case7() = b; // same as before
std::cin.get();
}
In all of your case functions except case6() you return by value so you do have an rvalue expression.
The reason case1() and and case2() don't work but the others do is because the assignment operator for built in types only works on lvalues. User defined types do not have such a restriction unless you add it yourself by adding a reference qualifier to the assignment operator.
Changing your copy assignment operator to
Foo operator=(Foo& other) & //<- notice the & at the end
{
std::cout << "copy assign used" << std::endl;
val = other.val;
return *this;
}
will cause all cases except case6() to not compile as the trailing & says you can only call the copy assignment operator on an lvalue.
You can't determine the value category of the return value by checking which constructors get called, because the compiler can in some cases elide copies and moves, eliminate a local variable used to hold a return value (NRVO), and convert copies into moves.
However, the value category rule is simple:
If the function's declared return type is an lvalue reference, then the return value is an lvalue.
If the function's declared return type is an rvalue reference, then the return value is an xvalue.
Otherwise, the return value is a prvalue.
(There is an exception for functions: function values are always lvalues.)

VC++ 15 calls the wrong copy constructor for lambda capture?

Consider the following program:
#include <iostream>
struct X {
X () = default;
X (X &) { std::cout << "non-const called" << std::endl; }
X (X const &) { std::cout << "const called" << std::endl; }
int i () const { return 7; }
};
auto f () {
X x;
auto lambda = [=]() { return x.i(); };
return lambda;
}
int main()
{
auto lambda = f();
std::cout << lambda () << std::endl;
return 0;
}
With VC++15, I get the output
const called
const called
7
With Clang 3.9, I get
non-const called
7
Which compiler is correct here?
I would say that clang is right.
The most suited constructor is called only once when the lambda captures x and the constructor for the returned value is optimized out.
That's why you obtain only one non-const called.
See here and here for further details about copy-elision and RVO.

unexpected output in copy constructor in the following code

#include < iostream >
using namespace std;
class A
{
public:
int x;
A(int i)
{
x= i;
cout<<"Constructor is Called "<<x<<endl;
}
~A()
{
cout<<"destructor is Called "<<x<<endl;
}
A(const A &a)
{
cout<<"in copy constructor a.x = "<<a.x<<endl;
cout<<" x = "<<x<<endl;
}
};
const A &fun(int i)
{
cout<<"in Fun"<<endl;
A t(i+1);
return(t);
}
main()
{
A *gg = new A(5);
A t = fun(2);
}
output of this is :
Constructor is Called 5
in Fun
Constructor is Called 3
destructor is Called 3
in copy constructor a.x = 0
x = 4067272
Why it is a.x=0 and x= 4067272?
Add code to initialize x in the copy constructor.
A(const A &a) : x(a.x)
//^^^^^^^^^^^^^^^ Missing code
{
cout<<"in copy constructor a.x = "<<a.x<<endl;
cout<<" x = "<<x<<endl;
}
Also,
fun returns a reference to a local variable. The reference is invalid after you return from fun. When you use A t = fun(2);, you are entering UB territory. You can't assume anything reasonable from it.
You can fix this by returning an object from fun instead of a const&.
A fun(int i)
{
cout<<"in Fun"<<endl;
A t(i+1);
return(t);
}

c++ operator int is called in the code why?

In the below code snippet
#include <iostream>
class A
{
public:
A(int i) : m_i(i) { }
public:
int operator()(int i = 0) const
{
return m_i + i;
}
operator int () const
{
return m_i;
}
operator float () const
{
return 0.0;
}
private:
int m_i;
friend int g(const A&);
};
int f(char c)
{
return c;
}
int g(const A& a)
{
return a.m_i;
}
int main()
{
A f(2), g(3);
int i = f;// call 1
std::cout << f(1) << g(f) << std::endl;// call 2
return 0;
}
I gave some comments like call 1 and call 2 in the main function.
I understood why operator int is called at call 1.
But I could not understand why at // call 2
Can some body explain me why it is so.
The function g is hidden by the g (of type A) in scope. So g(f) converts f to int then calls g.operator()(int) with the result of the conversion.
When you call g(f), A::operator()(int i=0) is called for g.
f must therefore be converted into an int, which is done via A::operator int() .
std::cout << f(1) << g(f) << std::endl;
Let's break this down into function calls instead of operators. (This might not be technically correct syntax.)
int temp1 = f.operator()(1);
ostream& temp2 = std::cout.operator<<(temp1);
// By the implementation of ostream::operator<<, temp2 is a reference to std::cout.
// The compiler doesn't know this, though, and must treat it as if it could be different.
int temp3 = f.operator int(); // Typecast since A::operator() expects an `int`.
int temp4 = g.operator()(temp3);
ostream& temp5 = temp2.operator<<(temp4);
// temp5 is another reference to std::cout.
temp5.operator<<(std::endl);
// Result discarded.