I have a situation where no constructor appears to be called:
#include <iostream>
using namespace std;
int main ()
{
class yoyo
{
public:
int i;
yoyo()
{
i = 0;
cout << "defaultly initialized to 0" << endl;
}
yoyo (int j) : i(j)
{
cout << "initialized to " << j << endl;
}
};
int i;
yoyo a;
cout << "Hello1, i: " << a.i << endl;
yoyo b(5);
cout << "Hello2, i: " << b.i << endl;
yoyo c = b; /* 1 */
cout << "Hello3, i: " << c.i << endl;
return 0;
}
Output is:
defaultly initialized to 0
Hello1, i: 0
initialized to 5
Hello2, i: 5
Hello3, i: 5
(Note: nothing between Hello2 and Hello3)
If I change the program to read as follows:
#include <iostream>
using namespace std;
int main ()
{
class yoyo
{
public:
int i;
yoyo()
{
i = 0;
cout << "defaultly initialized to 0" << endl;
}
yoyo (int j) : i(j)
{
cout << "initialized to " << j << endl;
}
};
int i;
yoyo a;
cout << "Hello1, i: " << a.i << endl;
yoyo b(5);
cout << "Hello2, i: " << b.i << endl;
yoyo c; c = b; /* 1 */
cout << "Hello3, i: " << c.i << endl;
return 0;
}
(The only difference is in he line marked by /* 1 */)
The output now is:
defaultly initialized to 0
Hello1, i: 0
initialized to 5
Hello2, i: 5
defaultly initialized to 0
Hello3, i: 5
Now there is a constructor call between Hello2 and Hello3. My question is, why is there no (visible) constructor call in the first case?
In the case of
yoyo c = b;
it's the copy constructor that is called.
And in the case of
yoyo c; c = b;
it's the copy assignment operator that is called.
If you don't provide any of them, the compiler will generate default versions for you.
If you want to create your own copy constructor, it could look like this:
yoyo(const yoyo& other)
: i(other.i)
{ std::cout << "copy constructor initialized\n"; }
The copy assignment operator looks like this:
yoyo& operator=(const yoyo& other)
{
i = other.i;
return *this;
}
Both of them defined inside the class definition of course.
In the first case:
yoyo c = b;
calls the copy constructor, which the compiler generates for you implicitly in this case.
yoyo c = b;
This is referred to as copy-initialization; the compiler-generated copy constructor will be called and c will be initialized with that copy. Also, the default constructor of c will be called.
c = b;
Here, this is not initialization, this is assignment. The compiler-generated assignment operator will be invoked on that line.
in your code,
yoyo c=b will call copy constructor.if you want to see it being called,you have to define it explicitely.
eg:
yoyo(const yoyo& obj)
{
this->i=obj.i; cout<<"copy constructor"<<endl;
}
in the second case it will call constructor and then the assignment operator
yoyo c; //constructor
c = b; //assignment operator for which only copying occurs
you can overload assignment operator as below
yoyo& operator=(yoyo& obj)
{
i = obj.i;
cout << "assignment operator" << endl;
}
Related
I have the following class where I need to make a copy constructor which copies a dynamically allocate array. However, in the code below it uses the constructor of C and not the copy constructor. How do I fix this?
#ifndef B_HH
#define B_HH
#include <iostream>
#include "C.hh"
class B {
public:
B() { std::cout << "Constructor B" << this << std::endl ; array = new C[len];}
B(const B& other): array(other.array) { std::cout << "Copy Constructor B" << this << std::endl ;
array = new C[len];
for(int i=0;i<len;i++)
{
array[i] = other.array[i];
}
}
~B() { std::cout << "Destructor B" << this << std::endl ; delete[] array;}
private:
C *array;
static const int len = 12;
} ;
#endif
And my class C looks like this:
#ifndef C_HH
#define C_HH
#include <iostream>
class C {
public:
C() { std::cout << "Constructor C" << this << std::endl ; }
C(const C&) { std::cout << "Copy Constructor C" << this << std::endl ; }
~C() { std::cout << "Destructor C" << this << std::endl ; }
private:
} ;
#endif
This line will call len number of default C constructors
array = new C[len];
Then this line should actually call the copy assignment operator
array[i] = other.array[i];
Add this line to C and you will see this is a copy assignment
C& operator=(const C&)
{
std::cout << "Copy Assignment Operator C" << this << std::endl;
/* do actual copying here */
}
How do I fix this?
Well, you don't need to. In this case that is the proper behavior. Since you need to make a deep copy when you do
array = new C[len];
In B's copy constructor you default construct len number of C's in the memory location new gives you. You then call copy assignment operator of C len times in
for(int i=0;i<len;i++)
{
array[i] = other.array[i];
}
Below is the snippet aimed to test the constructors. It was run in VS 2015.
In my opinion, "B b(B())" has the same function as "B b = B()", however, my code seems to say that they behave different.
I know there's copy elision by compiler optimization, but I think the default constructor should be called at least when execute "B b(B())".
Can anyone help point out where my misunderstood is?
class B
{
public:
B() {
++i;
x = new int[100];
cout << "default constructor!"<<" "<<i << endl;
cout << "x address:" << x << endl << "--------" << endl;
}
B(const B &b) //copy constructor
{
++i;
cout << "Copy constructor & called " << i<< endl
<< "--------" << endl;
}
B(B &&b)//move constructor
{
x = b.x;
++i;
b.x = nullptr;
cout << "Copy constructor && called" << i << endl
<<"x address:"<< x << endl << "--------" << endl;
}
void print()
{
cout << "b address:" << x << endl << "--------" << endl;
}
private:
static int i;
int *x;
};
int B::i = 0;
int main()
{
B b1; //default constructor
b1.print();
B b2 = B(); //default constructor only
b2.print();
B b3(B()); //????nothing called... why???
B b4 = b2; //copy constructor
B b5 = move(b2); //move constructor
b2.print();
return 0;
}
Note that B b(B()) is a function declaration, not a variable definition at all, then no constructor would be called.
According to Most vexing parse, B b(B()) is a function declaration, for a function named b which returns an object of type B and has a single (unnamed) parameter which is a pointer to function returning type B and taking no parameter.
You can solve it by using braces (list initlization (since C++11)), like
B b1( B{} );
B b2{ B() };
B b3{ B{} }; // preferable from C++11
#include <vector>
#include <iostream>
#include <memory>
using namespace std;
class A
{
static int k;
public:
A(){k++ ; cout << "constructor : " <<k<< endl;};
~A(){k--; cout << "destructor : " << k <<endl;};
void show() { cout<<"current value of k = "<<k<<endl; }
};
int A::k = 0;
int main( )
{
vector<A> test;
test.push_back(A());
test.emplace(test.end(), A());
test[0].show();
cout<<test.size()<<endl;
return 0;
}
Output:
constructor : 1
destructor : 0
constructor : 1
destructor : 0
destructor : -1
current value of k = -1
2
destructor : -2
destructor : -3
Why has the destructor been called too many times, as it should have been called just twice since the constructor only gets called twice? How to avoid this situation?
A compiler-generated copy constructor is being used, which doesn't increment k.
Include that explicitly in your source code, and all will be well.
You're making copies, but your trace output doesn't show that (and your k doesn't get incremented when it happens). So the "extra" destructor calls go with copy constructions.
You can remove one of the copies by using emplace properly:
test.emplace(test.end());
// ^ no A() here; that would be like doing test.push_back(A(A()))
but you still have a copy in the push_back itself.
Write a copy constructor so that your trace output accounts for those operations:
A(const A&) { k++; cout << "copy-constructor : " << k << endl; }
(I wouldn't bother with a move constructor, as that'll delete the copy assignment operator and all hell will break loose.)
Finished code:
#include <vector>
#include <iostream>
#include <memory>
using namespace std;
class A
{
static int k;
public:
A() { k++; cout << "constructor : " << k << endl; }
~A() { k--; cout << "destructor : " << k << endl; }
A(const A&) { k++; cout << "copy-constructor : " << k << endl; }
void show() { cout << "current value of k = " << k << endl; }
};
int A::k = 0;
int main()
{
vector<A> test;
test.push_back(A());
test.emplace(test.end(), A());
test[0].show();
cout << test.size() << endl;
}
Output:
constructor : 1
copy-constructor : 2
destructor : 1
constructor : 2
copy-constructor : 3
copy-constructor : 4
destructor : 3
destructor : 2
current value of k = 2
2
destructor : 1
destructor : 0
(live demo)
The source code :
#include <iostream>
#include <string>
using namespace std;
int counts = 0;
class A {
public:
A() {
cout << ">> A(" << ++counts << ") constructor" << endl;
}
A(const A& a) {
cout << ">> A(" << ++counts << ") copy constructor" << endl;
}
A& operator=(const A& a) {
cout << ">> A(" << ++counts << ") = constructor" << endl;
return *this;
}
};
A get_A()
{
A a1;
cout << "address of a1 = " << &a1 << endl;
return a1;
}
void test_1()
{
A a2 = get_A();
cout << "address of a2 = " << &a2 << endl;
}
int main()
{
test_1();
return 0;
}
The output :
>> A(1) constructor
address of a1 = 0x7fff5296daf8
address of a2 = 0x7fff5296daf8
My questions :
1. Why there is only one constructor invoked ? Should not the assignment constructor be invoked ?
2. Why the address of a1 and a2 are the same ?
The Return Value Optimisation (RVO) is a compiler optimisation which eliminates copying the temporary object that you create in get_a into test_1. This is why both objects have the same address - they are actually the exact same object. Your compiler is eliminating the redundant construct-and-copy, and just constructs the result in place.
Because of copy elision.
Because of copy elision.
Instead of the return value of get_A() being used to copy-construct a2, the compiler just directly allocates the return value at the call site.
You can see the behaviour you expect if you turn off copy elision in your compiler (-fno-elide-constructors in GCC and Clang).
I cannot understand the order of constructor and destructor calls? What will execute first in this statement A b=f(a)? Can someone please help me out?
#include<iostream>
using namespace std;
class A {
int x;
public:
A(int val = 0)
:x(val) {
cout << "A " << x << endl << flush;
}
A(const A& a) {
x = a.x;
cout << "B " << x << endl << flush;
}
void SetX(int x) {
this->x = x;
}
~A() {
cout << "D " << x << endl << flush;
}
};
A f(A a) {
cout << " C " << endl << flush;
a.SetX(100);
return a;
}
int main()
{
A a(1);
A b=f(a);
b.SetX(-100);
return 0;
}
Output Window:
A 1
B 1
C
B 100
D 100
D -100
D 1
Why does it print B 1 in line 2 of the output window?
"Why does it print B 1 in line 2?"
Because the copy constructor was called from this statement
A b=f(a);
The function f() requires A being passed by value, thus a copy for this parameter is made on the function call stack.
If your next question should be, how you can get over this behavior, and avoid to call the copy constructor, you can simply pass the A instance as a reference to f():
A& f(A& a) {
// ^ ^
cout << " C " << endl << flush;
a.SetX(100);
return a;
}
Side note: endl << flush; is redundant BTW, std::endl includes flushing already.