Empty user-defined move constructor - c++

The following code snippet which I was writing to understand move CTOR behaviour is giving me hard time to understand it's output:
#include <iostream>
class Temp
{
public:
Temp(){
std::cout << "Temp DEFAULT CTOR called" << std::endl;
mp_Val = nullptr;
}
Temp(int inp) {
std::cout << "Temp CTOR called" << std::endl;
mp_Val = new int(inp);
}
Temp(const Temp& inp) {
std::cout << "Temp COPY CTOR called" << std::endl;
mp_Val = new int(*inp.mp_Val);
}
Temp& operator= (const Temp& inp) {
std::cout << "Temp ASSIGNMENT OPER called" << std::endl;
mp_Val = new int(*inp.mp_Val);
return *this;
}
int* mp_Val;
};
class B
{
public:
B(){
std::cout << "Class B DEFAULT CTOR" << std::endl;
mp_Val = nullptr;
}
B(int inp) {
std::cout << "Class B CTOR" << std::endl;
mp_Val = new Temp(inp);
}
B(const B& in) {
std::cout << "Class B COPY CTOR" << std::endl;
mp_Val = in.mp_Val;
}
B(B&& in){
std::cout << "Class B MOVE CTOR" << std::endl; //Doubt: 1
}
Temp *mp_Val;
};
int main() {
B obj1(200);
B obj2 = std::move(obj1);
auto temp = obj1.mp_Val;
std::cout << "Obj1 B::Temp address: " << obj1.mp_Val << std::endl;
std::cout << "Obj2 B::Temp address: " << obj2.mp_Val << std::endl; //Doubt: 2
return 0;
}
Output:
Class B CTOR
Temp CTOR called
Class B MOVE CTOR
Obj1 B::Temp address: 0xd48030
Obj2 B::Temp address: 0x400880
GCC version: 4.6.3
My question is about the line marked as Doubt 2. Should not the address be printed as 0? As per my understanding, as I have defined an empty move CTOR (marked as Doubt 1) in class B, it should call the default CTOR of class Temp (which it's not calling as evident from the logs) to initialise its member variable mp_Val of type Temp.
There is obviously something that I am missing.

As per my understanding, as I have defined an empty move CTOR (marked as Doubt 1) in class B, it should call the default CTOR of class Temp (which it's not calling as evident from the logs) to initialise its member variable mp_Val of type Temp.
Your member variable isn't of type Temp, it's of type Temp *. You're right that the lack of an initialiser means that that member will be default-constructed, and for type Temp that would involve calling the default constructor. However, for pointer types, default construction leaves the object uninitialised.

Related

What Constructor is being called, it's not move

I created a basic test class to learn how the move constructor works. The move constructor does not seem to be called, and I'm not sure what constructor is actually called. If I use std::move then the move constructor is called, but a regular R value won't actually call it. Why is this happening, and what constructor is actually being called? I'm using g++ 4.6.3
#include <iostream>
#include <cstring>
class Test
{
int a;
int b;
int* c;
public:
Test(int one, int two)
{
std::cout << "Param Constructor" << "\n";
a = one;
b = two;
}
Test()
{
std::cout << "Default Constructor" << "\n";
a = 1;
b = 2;
}
~Test()
{
std::cout << "Deconstructor" << "\n";
}
Test(const Test& test)
{
a = test.a;
b = test.b;
std::cout << "Copy constructor called" << "\n";
}
Test(Test&& test)
{
std::cout << "Move constructor called" << "\n";
a = test.a;
b = test.b;
}
Test& operator=(const Test& test)
{
std::cout << "in operator=" << "\n";
a = test.a;
b = test.b;
return *this;
}
};
Test createTest()
{
return Test(1,2);
}
int main()
{
Test test(createTest());
Test test2 = test;
std::cout << "After logic" << "\n";
return 0;
}
The output I get:
Param Constructor
Copy constructor called
After logic
Deconstructor
Deconstructor
I create an object of type Test with the name test, but there is no output of it being created? I was expecting this output:
Param Constructor
Move Constructor // (Missing)
Deconstructor //Deleting instance from createTest (Missing)
Copy constructor called
After logic
Deconstructor
Deconstructor
what constructor is actually being called?
No constructor at all. Count the number of destructor calls. You'll find that there is one less than you expected. The temporary that you expected to be constructed wasn't created at all.
Why is this happening
The compiler avoided creation of the temporary. Instead, the object was constructed in place where it would have been moved to otherwise. This is known as copy elision.

How values of member variables are getting copied even though copy constructor is not getting called due to RVO in C++

I am not able to understand how the values of member variables are getting copied even though the constructor is not getting called in the below program.
#include <iostream>
using namespace std;
class myclass
{
public:
int x;
int y;
myclass(int a, int b)
{
cout << "In Constructor" << endl;
x = a;
y = b;
}
~myclass()
{
cout << "In Destructor" << endl;
}
myclass(const myclass &obj)
{
cout << "In Copy Constuctor " << obj.x << " " << obj.y << endl;
x = obj.x;
y = obj.y;
}
myclass &operator=(const myclass &obj)
{
cout << "In Operator Overloading" << obj.x << obj.y << endl;
x = obj.x;
y = obj.y;
return *this;
}
};
int main()
{
myclass obj1 = myclass(2, 3);
cout << "obj1.x : " << obj1.x << "obj1.y" << obj1.y << endl;
}
Output:
In Constructor
obj1.x : 2obj1.y3
In Destructor
I understood that due to Return Value Optimization, copy constructor is not getting called. But I didn't understand how obj1 is getting values 2 and 3. Can any one please help me to understand this or how Return Value Optimization will work behind the scenes.
The values aren't getting copied, because they don't need to be copied. Instead, the values which would have been copied are initialized in place. Copy elision means that the compiler essentially turns this:
myclass obj1 = myclass(2, 3);
Into this:
myclass obj1(2, 3);
So no extra object is constructed which needs to be copied.
Note that RVO, which you've referred to, is a form of copy elision. But this specific case of copy elision is not RVO.

why copy constructor is getting called even though I am actually copying to already created object in C++?

I wrote below code and I didn't understand why copy constructor is getting called.
#include <iostream>
using namespace std;
class abc
{
public:
abc()
{
cout << "in Construcutor" << (this) << endl;
};
~abc()
{
cout << "in Destrucutor" << (this) << endl;
};
abc(const abc &obj)
{
cout << "in copy constructor" << (this) << endl;
cout << "in copy constructor src " << &obj << endl;
}
abc& operator=(const abc &obj)
{
cout << "in operator =" << (this) << endl;
cout << "in operator = src " << &obj << endl;
}
};
abc myfunc()
{
static abc tmp;
return tmp;
}
int main()
{
abc obj1;
obj1 = myfunc();
cout << "OK. I got here" << endl;
}
when I ran this program, I am getting the following output
in Construcutor0xbff0e6fe
in Construcutor0x804a100
in copy constructor0xbff0e6ff
in copy constructor src 0x804a100
in operator =0xbff0e6fe
in operator = src 0xbff0e6ff
in Destrucutor0xbff0e6ff
OK. I got here
in Destrucutor0xbff0e6fe
in Destrucutor0x804a100
I didn't understand why copy constructor is getting called when I was actually assigning the object.
If I declare abc tmp, instead of static abc tmp in myfunc(), then copy constructor is not getting called. Can any one please help me to understand what is going on here.
Because you return an object by value from myfunc, which means it's getting copied.
The reason the copy-constructor is not getting called if you don't make the object static in myfunc is because of copy elision and return value optimization (a.k.a. RVO). Note that even though your copy-constructor may not be called, it still has to exist.

using std::move to prevent copying

I have the following code:
#include <iostream>
#include <vector>
struct A
{
std::vector<int> x;
A()
{
std::cout << "A()" << std::endl;
}
A(const A&)
{
std::cout << "A(const A&)" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
};
struct B : public A
{
std::vector<int> y;
B()
{
std::cout << "B()" << std::endl;
}
B(const A&a)
{
std::cout << "B(const A&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const A&&a)
{
std::cout << "B(const A&&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const B&)
{
std::cout << "B(const B&)" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
};
A ret_a()
{
A a;
a.x.resize(10);
return a;
}
int main()
{
std::cout << "section I" << std::endl << std::endl;
A a = ret_a();
B b(a);
std::cout << "a.x.size=" << a.x.size() << std::endl;
std::cout << std::endl << "section II" << std::endl << std::endl;
B b2(ret_a());
std::cout << "b.x.size=" << b.x.size() << std::endl;
std::cout << std::endl << "section III" << std::endl << std::endl;
return 0;
}
With output (VS2013, Release build)
section I
A()
A()
B(const A&)
a.x.size=10
section II
A()
A()
B(const A&&)
~A()
b.x.size=10
section III
~B()
~A()
~B()
~A()
~A()
Why a.x.size() within "section I" has size 10? I thought that std::move should move all data from a.x to y.x
Why did "section II" call constructor A() twice? I thought that B(const A&&) would prevent excessive copying of A
UPDATE
see fixed code at http://pastebin.com/70Nmt9sT
T&& and const T&& are not the same type. You almost never want a const rvalue reference - you can't steal its resources since you made it const! x = std::move(a.x); in B(const A&a) copies a.x since the return type of std::move(a.x) is const vector<int>&&.
The constructor, B(const A&&) calls the default constructor of A since it is derived from A, and the member initializer list does not make an attempt to construct the base A. This is the second A call.
Why a.x.size() within "section I" has size 10? I thought that std::move should move all data from a.x to y.x
This is because of B(const A&& a). Since a is const within that constructor, you only have const access to its member x, and calling std::move on a vector<T> const results in a vector<T> const&& which cannot bind to vector's move constructor (which takes a vector<T>&& argument). Instead it ends up calling the copy constructor, which leaves the source object unmodified.
Why did "section II" call constructor A() twice? I thought that B(const A&&) would prevent excessive copying of A
The first default construction occurs within the body of ret_a(). The second default construction is that of the A sub-object of B. To avoid the second one move the A instance in the member initializer list.
B(const A&&a)
: A(std::move(a))
{
std::cout << "B(const A&&)" << std::endl;
y.resize(x.size());
}
Note that the move doesn't actually result in moving the contents of a due to the same reason as explained above. Moreover, even modifying the signature to B(A&& a) would not result in the contents of a being moved because the user provided copy constructor and destructor definitions prevent implicit generation of a move constructor for A, and it'll be copied instead.

two different behavior in using default and overridden copy constructor

When I override copy constructor why it segfaults in first delete itself.
output:
$./a.out
inside ctor
inside copy-ctor
Say i am in someFunc
inside dtor
*** glibc detected *** ./a.out: free(): invalid pointer: 0xb75f3000 ***
if I do not override copy-ctor then I could see that s1.PrintVal() is getting called and then there is seg fault in *ptr that is expected.
Why there is two different behavior with and without default and overridden copy-ctor?
#include<iostream>
using namespace std;
class Sample
{
public:
int *ptr;
Sample(int i)
{
cout << "inside ctor" << endl;
ptr = new int(i);
}
Sample(const Sample &rhs)
{
cout << "inside copy-ctor" << endl;
}
~Sample()
{
cout << "inside dtor" << endl;
delete ptr;
}
void PrintVal()
{
cout <<" inside PrintVal()."<<endl;
cout << "The value is " << *ptr<<endl;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
return 0;
}
In your copy-ctor, you don't actually copy ptr, meaning its value will be unspecified, and you'll be deleting an unspecified pointer (instead of double-deleting a normal pointer as you do with the defauly copy-ctor).
The default copy ctor copies every member by value. This will create an alias to the pointer so each class when its dtor is called will delete the pointer and cause a fault.
In almost any class where you have a pointer that is being allocate you will need to write a custom copy constructor to allocate the pointer and then copy the value.
class Sample
{
public:
int *ptr;
Sample(int i)
{
cout << "inside ctor" << endl;
ptr = new int(i);
}
Sample(const Sample &rhs)
{
ptr = new int(*rhs.ptr);
}
Sample & operator=(const Sample& other)
{
// You should also override copy assignment if you overide copy
// you don't need to allocate in this case just copy the value
*ptr = *other.ptr;
}
~Sample()
{
cout << "inside dtor" << endl;
delete ptr;
}
void PrintVal()
{
cout <<" inside PrintVal()."<<endl;
cout << "The value is " << *ptr<<endl;
}
};
You should look up the rule of three and if your in c++ 11 the rule of five