I'm trying to know more about rvalue references but I got stuck on this simplest example:
#include <iostream>
using namespace std;
struct C {
C() { cout << "C()\n"; }
~C() { cout << "~C()\n"; }
C(const C&) { cout << "C(const C&)\n"; }
C& operator=(const C&) { cout << "operator=(const C&)\n"; return *this; }
C(C&&) { cout << "C(C&&)\n"; }
C& operator=(C&&) { cout << "operator=(C&&)\n"; return *this; }
};
C foo() { C c; return c; }
int main()
{
const C c = foo();
return 0;
}
I've compiled it with Clang 3.2 and -std=c++11 -fno-elide-constructors (to avoid (N)RVO) but the result is surprising to me:
C()
~C() // huh?
C(C&&)
~C()
~C()
I expected exactly that except for the first ~C(). Where did it came from and what am I missing because there are 2 constructions and 3 destructions? Is the && constructor called with a destroyed object reference??
This must be a bug. The destructor for the local object constructed in foo() is being invoked before the move constructor of the receiving object. In particular, it seems a temporary is allocated but not (move-)constructed when returning by value. The following program shows this:
#include <iostream>
using namespace std;
struct C
{
C(int z) { id = z; cout << "C():" << id << endl; }
~C() { cout << "~C():" << id << endl; }
C(const C& c) { id = c.id + 1; cout << "C(const C&):" << id << endl; }
C& operator=(const C&) { cout << "operator=(const C&)\n"; return *this; }
C(C&& c) { id = c.id + 1; cout << "C(C&&):" << id << endl;}
C& operator=(C&&) { cout << "operator=(C&&)\n"; return *this; }
int id;
};
C foo() { C c(10); return c; }
int main()
{
const C c = foo();
return 0;
}
Output:
C():10
// THE TEMPORARY OBJECT IS PROBABLY ALLOCATED BUT *NOT CONSTRUCTED* HERE...
~C():10 // DESTRUCTOR CALLED BEFORE ANY OTHER OBJECT IS CONSTRUCTED!
C(C&&):4198993
~C():4198992
~C():4198993
Creating two objects inside of foo() seems to shed some more light on the issue:
C foo() { C c(10); C d(14); return c; }
Output:
C():10
C():14
~C():14
// HERE, THE CONSTRUCTOR OF THE TEMPORARY SHOULD BE INVOKED!
~C():10
C(C&&):1 // THE OBJECT IN main() IS CONSTRUCTED FROM A NON-CONSTRUCTED TEMPORARY
~C():0 // THE NON-CONSTRUCTED TEMPORARY IS BEING DESTROYED HERE
~C():1
Interestingly, this seems to depend on how the object is constructed in foo(). If foo() is written this way:
C foo() { C c(10); return c; }
Then the error appears. If it is written this way it does not:
C foo() { return C(10); }
Output with this last definition of foo():
C():10 // CONSTRUCTION OF LOCAL OBJECT
C(C&&):11 // CONSTRUCTION OF TEMPORARY
~C():10 // DESTRUCTION OF LOCAL OBJECT
C(C&&):12 // CONSTRUCTION OF RECEIVING OBJECT
~C():11 // DESTRUCTION OF TEMPORARY
~C():12 // DESTRUCTION OF RECEIVING OBJECT
Related
I meet a course programming problem, which asks me to initialize the A a using passing by reference (initialize the A a in the func). How can I call A's constructor by A's reference?
#include <iostream>
using namespace std;
class A
{
public:
int x;
A()
{
cout << "default constructor" << endl;
x = 1;
}
A(int x)
{
cout << "constructor with param = " << x << endl;
this->x = x;
}
~A() {
cout << "destructor" << endl;
}
void print() {
cout << x << endl;
}
};
void fun(A& a)
{
a.A::A(10); // error!
return;
}
int main()
{
A a;
fun(a);
a.print();
return EXIT_SUCCESS;
}
There is a background of this problem. The teacher want us to replicate the NRVO(named return value optimization) result.
#include <iostream>
using namespace std;
class A
{
public:
int x;
A()
{
cout << "default constructor" << endl;
x = 1;
}
A(int x)
{
cout << "constructor with param = " << x << endl;
this->x = x;
}
~A() {
cout << "destructor" << endl;
}
void print() {
cout << x << endl;
}
};
A fun() {
A a = A(10);
return a;
}
int main()
{
A a = fun();
return EXIT_SUCCESS;
}
default g++ compiler:
constructor with param = 10
destructor
if we close the NRVO:
g++ test.cpp -fno-elide-constructors
constructor with param = 10
destructor
destructor
destructor
destructor
The teacher want us to replicate the NRVO(named return value optimization) result by passing by reference.
The syntax a.A::A(10); is incorrect.
Constructor is used to create an object of a class, you cannot call it on an already existing object. Even a constructor cannot be explicitly called. It is implicitly called by the compiler.
From general-1.sentence-2:
Constructors do not have names.
Thus, you cannot call a constructor explicitly. The compiler will automatically call the constructor when an object of that class-type is created.
You can not, not like this.
A reference always points to an initialized object. So you already failed before you called the function. The "return" argument is already initialized. And you can't initialized an initialized value again, not legally.
You can cheat by calling
std::construct_at(&a, 10);
For it to really reflect NRVO you could have something like this:
void fun(A *a)
{
std::construct_at(a, 10);
}
union UninitializedA {
std::byte uninitialized[sizeof(A)];
A a;
};
int main()
{
UninitializedA u;
fun(&u.a);
u.a.print();
u.a.~A();
return EXIT_SUCCESS;
}
At the last line myA = foo(myOtherB);, the function will return type an object of type A, thus; it will be like saying `myA = input, But why is the copy constructor is being?
output:
B foo()
A copy ctor //what calls this?
A op=
For a copy constructor to be called we will have to use the assignment operator during initialization such as: B newB = myOtherB;
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A ctor" << endl; }
A(const A& a) { cout << "A copy ctor" << endl; }
virtual ~A() { cout << "A dtor" << endl; }
virtual void foo() { cout << "A foo()" << endl; }
virtual A& operator=(const A& rhs) { cout << "A op=" << endl; }
};
class B : public A {
public:
B() { cout << "B ctor" << endl; }
virtual ~B() { cout << "B dtor" << endl; }
virtual void foo() { cout << "B foo()" << endl; }
protected:
A mInstanceOfA; // don't forget about me!
};
A foo(A& input) {
input.foo();
return input;
}
int main() {
B myB;
B myOtherB;
A myA;
myOtherB = myB;
myA = foo(myOtherB);
}
At the last line myA = foo(myOtherB);, the function will return type an object of type B
Not true. Your function returns an object of type A by value. That means, any value you feed this object to be constructed with will be used to construct a new object of that exact type. So in other words:
int foo(float a) {
return a + 0.5;
}
int u;
u = foo(9.3);
// u has a value of 10
Don't expect u to hold a value that a int cannot.
Same thing if you use user defined types:
A foo(A& input) {
input.foo();
return input; // this expression returns a new A
// using the value of `input`
}
A myA;
myA = foo(myOtherB);
// why would `myA` be anything else than the value of an A?
So then, what happen here?
B foo()
A copy ctor //what calls this?
A op=
A foo(A& input) {
input.foo(); // prints B foo, virtual call. a reference to A that
// points to an object of subclass type B
return input; // copy `input` into the return value object
}
Then, the operator= gets called.
See cppreference
Specifically:
The copy constructor is called whenever an object is initialized (by direct-initialization or copy-initialization) from another object of the same type (unless overload resolution selects a better match or the call is elided), which includes
initialization: T a = b; or T a(b);, where b is of type T;
function argument passing: f(a);, where a is of type T and f is void f(T t);
function return: return a; inside a function such as T f(), where a is of type T, which has no move constructor.
I'm using visual studio 2010 compiler and I'm trying to understand the output of this program.
Code:
#include <iostream>
using namespace std;
class A
{
public:
int i;
A()
{
i=0; cout<<"constructing A..\n";
}
A(int a): i(a)
{
cout<<"constructing A with argument\n";
}
A(A& a)
{
i=a.i;
cout<<"copy constructor\n";
}
~A()
{
cout<<"destructing a: " << i << endl;
}
};
A& f(A b)
{
return A(25);
}
void main()
{
A m;
cout << "i = " << f(m).i << endl;
}
Output:
constructing A..
copy constructor
constructing A with argument
destructing a: 25
destructing a: 0
i = 25
destructing a: 0
From my understanding, A(25) returned by reference and then destroyed, so why does it print the value of i: 'i = 25'?
The program has undefined behavior. Nevertheless the output can be as you expected because the memory occupied by the non alive object can be not overwritten yet.
In the code show below, how do I assign rvalue to an object A in function main?
#include <iostream>
using namespace std;
class A
{
public:
int* x;
A(int arg) : x(new int(arg)) { cout << "ctor" << endl;}
A(const A& RVal) {
x = new int(*RVal.x);
cout << "copy ctor" << endl;
}
A(A&& RVal) {
this->x = new int(*RVal.x);
cout << "move ctor" << endl;
}
~A()
{
delete x;
}
};
int main()
{
A a(8);
A b = a;
A&& c = A(4); // it does not call move ctor? why?
cin.ignore();
return 0;
}
Thanks.
Any named instance is l-value.
Examples of code with move constructor:
void foo(A&& value)
{
A b(std::move(value)); //move ctr
}
int main()
{
A c(5); // ctor
A cc(std::move(c)); // move ctor
foo(A(4));
}
When I compile the following code with g++, the object of class A seems not to be destructed when the object of class C is constructed, and the B.ref_a reference is not broken when accessed by the constructor of object of class C:
#include <iostream>
struct A
{
A(int aa)
{
a = aa;
}
~A()
{
std::cout << "A out" << std::endl;
}
int a;
};
struct B
{
B(const A& a)
: ref_a(a)
{
}
~B()
{
std::cout << "B out" << std::endl;
}
const A& ref_a;
};
struct C
{
C(const B& b)
{
c = b.ref_a.a + 1;
}
int c;
};
int main(void)
{
C c(B(A(1)));
std::cout << c.c << std::endl;
}
However, is it guaranteed by the C++ language?
Here, the temporary objects go out of scope when the instruction has finished its execution. That is, just after the constructor of C has returned.
And yes, this is guaranteed by the C++ standard.