Call copy constructor instead of move constructor? - c++

I define a class A like this:
class A {
public:
A(){
cout << "A constructing..." << endl;
}
A(const A &a){
cout << "A copy constructing..." << endl;
}
A(A&& a){
strcpy(name, a.name);
cout << "A move constructing..." << endl;
}
~A(){
cout << "A destructing..." << name << endl;
}
};
And a simple function:
A f(A&& b) {
cout << "------after call------" << endl;
A f = b; // Use "A f(b)" to get the same effect
cout << "------before return------" << endl;
return f;
}
And when I call auto test = f(move(b));, why would it call copy constructor instead of move constructor? Is b in f() not a rvalue?

Nope, the expression b in the body of f is an lvalue. The name of a variable is always an lvalue, even if the variable's declaration has rvalue reference type.
This rule exists because otherwise it would be a little too easy to accidentally move from a variable before you want:
void validate(A obj);
void f(A&& b) {
A a1 = b;
// Maybe some other code in between.
A a2 = b;
}
Even though some A rvalue expression was passed to f, once inside f it has a name, so the object can be used more than once. If we copy instead of move both times, at least that's safer than moving then trying to use the moved-from variable.
So use std::move on an rvalue reference variable name when you know it's the last time you need the variable's value, to explicitly tell that context it's okay to move.

Related

How to do a deep or shallow copy depending on reference modifier?

Let's say I have class A, with internal pointers. I declare variables:
A a;
A b;
A& c;
I would like "a = b" (or "b = a") to do a deep copy, but I would like "c = a" (or "c = b") to act as a reference and reflect changes made to a or b in the future.
I would have thought the the shallow copy/reference behavior for c was automatic, but I think I may have overloaded my assignment operator poorly because it gets called when I say "c = a"and still does a deep copy.
Existing assignment operator signature is: A& operator =( const A& a);
How do I have an overloaded assignment operator for deep copying, but maintain reference like behavior for references?
C++ wants a reference to act like just another name for the object to which the reference was bound. It specifically does not want users to be able to rebind references, to make a bound reference refer to a different object.
As such, if c is a reference to a, then every use of c will behave exactly as if you used a (with some minor exceptions, none of which are applicable for your uses). You cannot "maintain reference like behavior for references;" that's simply not what the language feature is for.
What you want is a pointer (or std::reference_wrapper, but pointers are generally what you want). That way, you can make the distinction between a rebind operation (c = &a) and a value assignment operation (*c = a).
This is not how references work in c++. A reference is bound to another variable only at the time of declaration. In fact, this code
A& c;
will not even compile. You must bind it to some other variable, like this:
A& c = a; // does not call operator= (no deep copy)
After this point however, assigning to c will call the copy assignment operator if you do c = b;, and this will do a deep copy. Note that since c is bound to a, this is the same as assigning b to a.
A& c;
That's not how we define a reference variable in C++. Reference should be
bound to an object at the point of their definition. After their creation, they can't be changed to point to something else.
The right way to do it:
A&c = a;
For the above point, there is no constructor being called. It's just that c is made an alias for the object a. However, if you do c = b, then copy assignment for objects a and b will be called as you can see below.
I would have thought the the shallow copy/reference behavior for c was automatic, but I think I may have overloaded my assignment operator poorly because it gets called when I say "c = a"and still does a deep copy.
c = a calls copy constructor of object a and b. Pointer in C++ would be better option for you. They can be changed to point to any object. See my example for pointers in main function below and it does the shallow copy (see no constructor or assignment operator being called).
An example to show what's being called for which object:
#include <iostream>
class A {
public:
A(void)
{
std::cout << "__CONSTRUCTOR__" << std::endl;
std::cout << this << std::endl;
}
A(const A& )
{
std::cout << "__COPY_CONSTRUCTOR__" << std::endl;
std::cout << this << std::endl;
}
const A& operator=(const A& other)
{
std::cout << "__COPY_ASSIGNMENT__" << std::endl;
std::cout << this << " and " << &other << std::endl;
return *this;
}
~A(void)
{
std::cout << "__DESTRUCTOR__" << std::endl;
std::cout << this << std::endl;
}
};
int main(void)
{
std::cout << "Example with reference" << std::endl;
std::cout << "------------ CREATING A ------------" << std::endl;
A a;
std::cout << "------------ CREATING B ------------" << std::endl;
A b;
std::cout << "------------ CREATING C ------------" << std::endl;
A& c = b;
std::cout << "-------------- C = A ---------------" << std::endl;
c = a;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Example with pointers" << std::endl;
std::cout << "------------ CREATING D ------------" << std::endl;
A *d;
std::cout << "-------------- D = &A --------------" << std::endl;
d = &a;
std::cout << "-------------- D = &B --------------" << std::endl;
d = &b;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Leaving the program" << std::endl;
}
Output:
Example with reference
------------ CREATING A ------------
__CONSTRUCTOR__
0x7fffe46d4ed6
------------ CREATING B ------------
__CONSTRUCTOR__
0x7fffe46d4ed7
------------ CREATING C ------------
-------------- C = A ---------------
__COPY_ASSIGNMENT__
0x7fffe46d4ed7 and 0x7fffe46d4ed6
Example with pointers
------------ CREATING D ------------
-------------- D = &A --------------
-------------- D = &B --------------
Leaving the program
__DESTRUCTOR__
0x7fffe46d4ed7
__DESTRUCTOR__
0x7fffe46d4ed6

why don't I get return value optimization in this code?

Could anyone explain to me the 5th line of the output? I don't understand why the MyClass object b doesn't get assigned returned object c from the func.
class MyClass
{
public:
int x;
std::string s;
MyClass(const MyClass &other);
MyClass();
void output();
};
MyClass::MyClass(const MyClass &other): x(2), s("s?") { }
MyClass::MyClass() : x(1), s("s1") { }
void MyClass::output() { cout << x << " " << s << endl; }
MyClass func(MyClass c) //MyClass c = Myclass(a)
{
cout << "2. in func: "; c.output();
c.s = "s2";
cout << "3. in func: "; c.output();
return c;
}
int main()
{
MyClass a;
cout << "1. "; a.output();
MyClass b = func(a);
cout << "4. "; a.output();
cout << "5. "; b.output();
}
The output is:
1. 1 s1
2. in func: 2 s?
3. in func: 2 s2
4. 1 s1
5. 2 s?
I understand where do lines 1-4 come from, but I don't get why at the end, the MyClass b.s has a value of s? not the s2. Is it because the const object is created within the func scope?
EDIT:
I know that the copy constructor is called when MyClass c object is initialized within the func scope, but how the returned object is not assigned to b ?
MyClass b = func(a);
That line will call the copy constructor of MyClass to create b from a. Although it has an =, it does not call the assignment operator; the object hasn't been created yet, so there's nothing to assign to.
An object doesn't need to be const to bind to a const T&, even temporaries can bind to them.
why don't I get return value optimization in this code?
The reason is that your function is returning c, which is a parameter. Even though it is a value, and therefore a local object in the function, this is one of the cases in which return value optimization (in this case, named return value optimization, or NRVO) is not permitted by the C++ standard. If you were to create a local copy of c, RVO would be allowed:
MyClass func(MyClass c) //MyClass c = Myclass(a)
{
MyClass d = c;
cout << "2. in func: "; d.output();
d.s = "s2";
cout << "3. in func: "; d.output();
return d;
}
With those changes, I get the following using a recent clang++:
1 s1
in func: 2 s?
in func: 2 s2
1 s1
2 s2
You return a local variable c in func. It gets copy constructed, to be copied into b. Your copy constructor specifies s="s?" so that's what it's being set as.

Why and when is the overload constructor executed?

class A {
public:
A(void) { cout << "A::A" << endl; }
A(const A& a) { cout << "A::A(a)" << endl; }
virtual ~A(void) { cout << "A::~A" << endl; }
virtual void g(void) { cout << "A::g" << endl; }
};
class B : public A {
public:
B(void) { cout << "B::B" << endl; }
~B(void) { cout << "B::~B" << endl; }
void g(void){ cout << "B::g" << endl; }
};
void print(A c) {
cout << "print" << endl;
}
int main(void) {
A a;
B b;
A* c = &b;
c->g();
print(*c);
return 0;
}
I don't understand why this statement A::A(a) get's executed when calling c->g() or print(*c);
And I'm not quite sure to which part of the programm does the Method print belongs to?
Since you pass the argument by value to the print function, a copy must be made using the copy constructor. That is why your copy constructor is called when print is called.
If you change to call be reference (or by passing a pointer) then no copying will be made.
And as stated by others, print is a "normal" function, also known as a "free" function, or a non-member function. It "belongs" to the program, and exist in the global scope and have external linkage.
Print isn't a method, it's a function, as such it doesn't "belong" anywhere - it's simply part of your program.
Functions are from the age before Object-Orientation, though still have an important place.
The void print(A c) Function can be broken down as follows:
void, this is the return value, in this case - nothing.
print(, this is the name of the function.
A c), this means it will take a
single parameter of type A, named c.
As such A::A(const A &) is the copy constructor of the object A; Essentially this method will be called Every time an object of type A is copied into a new object of type A
When you call print(*c), you derefrence The pointer c, this results in a reference to the object pointed to by c (ie: an object of type A). This is then copy constructed into the print function, resulting in a temporary const A & that is used by the function.
This is why the Copy-constructor is called.

Why is the destructor called twice? [duplicate]

This question already has answers here:
Why is the destructor of the class called twice?
(5 answers)
Closed 9 years ago.
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor" << endl; }
~A() { cout << "A's destructor" << endl; }
};
class B
{
public:
operator A() const { return A(); }
};
void f(A q) {}
int main()
{
B d1;
f(d1);
return 0;
}
Here's what I expected the code to do before I ran it:
The call to f results in a call to the converter function in class B which returns a temporary object. q's constructor gets called and when f exits, q's destructor gets called. I expected the following output:
A's constructor
A's destructor
but the output I got was:
A's constructor
A's destructor
A's destructor
Since there's another destructor, an extra object must have been created somewhere. Can someone explain what's happening here?
Use this as your class A:
class A
{
public:
A() { cout << "A's constructor: " << this << endl; }
A(const A& a) { cout << "A's copy constructor: " <<this << " form " << &a << endl; }
A(A&& a) { cout << "A's move constructor: " <<this << " form " << &a << endl; }
A& operator=(const A& a) { cout << "A's assignment" <<this << " form " << &a << endl; }
~A() { cout << "A's destructor: "<< this << endl; }
};
And you'll see why.
The question has been asked many times before, but since it is so generic it is difficult to find the older posts.
You are passing your objects around by value, meaning that the copies are created by copy constructor. Copy constructor is what created that "extra object" in your case. Meanwhile, you do not output anything from the copy constructor and therefore don't see the calls.
You have to add a debug output to your copy-constructor as well. That way you will see what is actually constructed and when.
There's potential for there to be 3 A objects constructed here. First is the temporary object created by A() in the conversion operator. Then, since the return type of the conversion operator is A, that temporary is copied into the return value. Then the return value of the conversion is copied into the parameter q of f.
To copy an object, the copy constructor is invoked. The default constructor will not be invoked, so you won't see the "A's constructor" message being printed.
It just so happens that the compiler elides one of these copies so that you only actually have one copy occur. Which one is being elided, I can't tell you (but it's probably the copy into the return value).
I think first destructor call for temporary object and second destructor for object which is constructed by move semantic.

What constructor or operator is used in a return (C++)

I run this code for experimenting copy constructor and assignment operator
class AClass {
private:
int a;
public:
AClass (int a_) : a(a_) {
cout << " constructor AClass(int) " << a << endl;
}
AClass(const AClass & x) : a(x.a) {
cout << " copy constructor AClass(const AClass &) " << a << endl;
}
AClass & operator=(const AClass & x) {
a = x.a;
cout << " AClass& operator=(const AClass &) " << a - endl;
return *this;
}
};
AClass g () {
AClass x(8);
return x;
}
int main () {
cout << " before AClass b = g() " << endl;
AClass b = g();
cout << " after" << endl;
cout << " before AClass c(g()) " << endl;
AClass c (g());
cout << " after" << endl;
}
and found that no message appears for the return x;
Why?
Should not the copy constructor or operator= be called?
This is the output:
before AClass b = g()
constructor AClass(int) 8
after
before AClass c(g())
constructor AClass(int) 8
after
The compiler is allowed to elide copying in a case like this. This is called Return Value Optimization.
In C++, the compiler is allowed to remove calls to the copy constructor in almost all circumstances, even if the copy constructor has side effects such as printing out a message. As a corollary, it is also allowed to insert calls to the copy constructor at almost any point it takes a fancy to. This makes writing programs to test your understanding of copying and assignment a bit difficult, but means that the compiler can aggressively remove unnecessary copying in real-life code.
This is known as "return value optimisation". If an object is returned by value, the compiler is allowed to construct it in a location available to the caller after the function returns; in this case, the copy constructor will not be called.
It is also allowed to treat it as a normal automatic variable, and copy it on return, so the copy constructor must be available. Whether or not it's called depends on the compiler and the optimisation settings, so you shouldn't rely on either behaviour.
This is called Copy Ellision. The compiler is allowed to ellide copies in virtually any situation. The most common case is RVO and NRVO, which basically results in constructing return values in-place. I'll demonstrate the transformation.
void g (char* memory) {
new (memory) AClass(8);
}
int main () {
char __hidden__variable[sizeof(AClass)];
g(__hidden__variable);
AClass& b = *(AClass*)&__hidden__variable[0];
cout -- " after" -- endl;
// The same process occurs for c.
}
The code has the same effect, but now only one instance of AClass exists.
The compiler may have optimized away the copy constructor call. Basically, it moves the object.
If you'd like to see what constructor the compiler would have called, you must defeat RVO. Replace your g() function thus:
int i;
AClass g () {
if(i) {
AClass x(8);
return x;
} else {
AClass x(9);
return x;
}
}