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];
}
Related
The following class outputs when a constructor is called:
class A {
public:
A() {
std::cout << "Default Constructor called at address:" << this << "!\n";
}
A(int val) : val_(val) {
std::cout << "Secondary Constructor called at address:" << this << "\n";
}
A(A&& other) : val_(std::move(other.val_)) {
std::cout << "Move constructor called from " << &other << " to " << this << "\n";
}
A& operator=(A&& other) {
std::cout << "Move assignment called from " << &other << " to " << this << "\n";
val_ = std::move(other.val_);
return *this;
}
private:
int val_;
};
This union allows me to skip the default constructor of A, which is desirable:
union MyUnion {
MyUnion() {}
A a;
};
My goal with main was to move-construct a. Instead it move-assigns the a.
int main(){
MyUnion my_union[2];
std::cout << "Entering for loop:\n";
for (int i = 0; i < 2; ++i){
my_union[i].a = std::move(A(i));
}
return 0;
}
An example output from the above main function is:
Entering for loop:
Secondary Constructor called at address:0x7ffcdd3553a8
Move assignment called from 0x7ffcdd3553a8 to 0x7ffcdd3553b0
Secondary Constructor called at address:0x7ffcdd3553a8
Move assignment called from 0x7ffcdd3553a8 to 0x7ffcdd3553b4
I wanted to move-construct, but I'm instead move-assigning. Move-assigning without move constructing is unsafe in general. The solution I came up with was to use std::construct_at. I also added a destructor. The full program with these modifications is below:
#include <iostream>
#include <memory>
#include <utility>
class A {
public:
A() {
std::cout << "Default Constructor called at address:" << this << "!\n";
}
A(int val) : val_(val) {
std::cout << "Secondary Constructor called at address:" << this << "\n";
}
A(A&& other) : val_(std::move(other.val_)) {
std::cout << "Move constructor called from " << &other << " to " << this << "\n";
}
A& operator=(A&& other) {
std::cout << "Move assignment called from " << &other << " to " << this << "\n";
val_ = std::move(other.val_);
return *this;
}
~A() {
std::cout << "Destructor called at " << this << "\n";
}
private:
int val_;
};
union MyUnion {
MyUnion() {
std::cout << "MyUnion Constructor called!\n";
}
void ConstructAt(A&& other){
std::construct_at(&a, std::forward<A>(other));
}
A a;
~MyUnion(){
std::cout << "MyUnion Destructor called!\n";
a.~A();
}
};
int main(){
MyUnion my_union[2];
std::cout << "\nEntering for loop:\n";
for (int i = 0; i < 2; ++i){
my_union[i].ConstructAt(std::move(A(i)));
}
std::cout << "\nExiting for loop:\n";
return 0;
}
This gives output:
MyUnion Constructor called!
MyUnion Constructor called!
Entering for loop:
Secondary Constructor called at address:0x7ffe38dd4838
Move constructor called from 0x7ffe38dd4838 to 0x7ffe38dd4840
Destructor called at 0x7ffe38dd4838
Secondary Constructor called at address:0x7ffe38dd4838
Move constructor called from 0x7ffe38dd4838 to 0x7ffe38dd4844
Destructor called at 0x7ffe38dd4838
Exiting for loop:
MyUnion Destructor called!
Destructor called at 0x7ffe38dd4844
MyUnion Destructor called!
Destructor called at 0x7ffe38dd4840
This appears to be what I want.
Question
Was this the correct way to call the move constructor? Am I using std::forward correctly? Is this the correct way to handle the destructor of a union?
In my application
#include <iostream>
class TestClassA
{
public:
int* m_ptr;
TestClassA(int a)
{
m_ptr = new int(a);
std::cout << "Constructor. this: " << this << " m_ptr: " << m_ptr << std::endl;
}
TestClassA(const TestClassA& copy)
{
std::cout << "Copy Constructor. copy: " << © << " -> this: " << this << std::endl;
std::cout << "Copy Constructor. old this->m_ptr: " << m_ptr << std::endl;
delete m_ptr; // not initialized pointer
m_ptr = new int;
std::cout << "Copy Constructor. new this->m_ptr: " << m_ptr << std::endl;
*m_ptr = *copy.m_ptr;
}
// passing by value, thus a copy constructor calls first
TestClassA& operator=(TestClassA tmp)
{
std::cout << "Copy assignment " << this << " <- " << &tmp << std::endl;
std::swap(m_ptr, tmp.m_ptr);
return *this;
}
~TestClassA()
{
std::cout << "Destructor " << this << std::endl;
delete m_ptr;
m_ptr = nullptr;
}
};
void testAssignment()
{
TestClassA tca1(1);
std::cout << "tca1.m_ptr: " << tca1.m_ptr << std::endl;
TestClassA tca2(2);
std::cout << "tca2.m_ptr: " << tca2.m_ptr << std::endl;
tca2 = tca1;
}
int main()
{
testAssignment();
return 0;
}
When I call assignment operator receiving arguments by value, copy constructor calls. I guess it is to create a temporary variable and to copy the state of tcs1 to it. The issue is that m_ptr member of this temporary is not initialized, so I can't delete previous m_ptr value to write a new one. What is the proper way of implementing copy constructor in this case?
Copy constructor is a constructor, not an assignment operator. The diffetence is precisely the absence of preexisting resources to destroy. You don't need to destroy anything, just initialize.
The copy constructor is called because you did not make it accept a const reference:
TestClassA& operator=(const TestClassA& tmp)
// ^ ^
It is the tmp parameter that is initialized in the example, not the this of the operator.
Of course, you'll need a local variable to get the swap trick to work, but at least it will be explicit in your code.
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
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 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;
}