I'm kind of confused, because I was sure this should work different. Take a look at this code example:
#include <iostream>
#include <string>
using namespace std;
class base
{
public:
virtual ~base() = default;
};
class derived : public base
{
private:
int a = 0;
int *b = nullptr;
std::string lol;
public:
derived(std::string s) : b(new int(6)), lol{s} { cout << "ctor " << lol << endl; }
derived(derived const& d) : lol{d.lol + " copy"} {cout << "copy " << lol << endl; }
virtual ~derived() { cout << "dtor " << lol << endl; delete b; }
virtual void superFunction() { cout << "OMG " << lol << endl; }
};
int main()
{
derived a("a");
derived b("b");
a = b;
}
And the program output with all optimizations off is:
ctor a
ctor b
dtor b
dtor b
I was sure that in this case compiler should generate code that deletes object a and uses copy constructor to create new object. Instead it uses operator= that it implicitly declares.
Can someone explain why? Or point me to C++ standard.
Thanks.
When you write a = b;, compiler calls assignment operator, which will be automatically generated if not present in the code and not marked as deleted. Copy constructor is used only if you try to initialize a new object from another object like this:
derived a("a");
derived b = a;
Also, your code crashes before main returns as it tries to delete b, which points to the same memory from a and from b after a = b; default-assignment.
If you want to delete a with derived destructor after a = b; execution, all you need is copy-and-swap idiom. What is the copy and swap idiom? has a great answer on how to do that in legacy and modern C++. Proper implementation of rule-of-four from that answer will perfectly fit the DRY principle and help you to avoid memory issues. Note the fabulous trick with passing parameter to operator= by value, which makes compiler select the appropriate constructor (copy or move) and allows you to write only four methods instead of all five of them.
Related
I'm trying to have a vector of pointers to vectors of differents classes and where each classes is derived from a same base class.
My code:
#include <iostream>
#include <vector>
#include <stdlib.h>
class A
{
public:
A() { std::cout << "A constructor.\n"; }
virtual ~A() { std::cout << "A destructor\n"; }
virtual void iAm() { std::cout << "I am A.\n"; }
};
class B : public A
{
public:
B() { std::cout << "B constructor.\n"; }
~B() { std::cout << "B destructor.\n"; }
virtual void iAm() { std::cout << "I am B.\n"; }
private:
std::string s;
};
class C : public A
{
public:
C() { std::cout << "C constructor.\n"; }
~C() { std::cout << "C destructor.\n"; }
virtual void iAm() { std::cout << "I am C.\n"; }
private:
std::string s;
int n;
};
int main()
{
std::vector<std::vector<A>*> vect;
vect.resize(3);
vect[0]=new std::vector<A>;
vect[1]=(std::vector<A>*) new std::vector<B>;
vect[2]=(std::vector<A>*) new std::vector<C>;
vect[0]->push_back(A());
vect[0]->push_back(A());
vect[1]->push_back(B(methods are A methods));
vect[1]->push_back(B());
vect[2]->push_back(C());
vect[2]->push_back(C());
(*vect[0])[0].iAm();
(*vect[0])[1].iAm();
(*vect[1])[0].iAm();
(*vect[1])[1].iAm();
(*vect[2])[0].iAm();
(*vect[2])[1].iAm();
}
But the execution give me:
A constructor.
A destructor.
A constructor.
A destructor.
A destructor.
A constructor.
B constructor.
B destructor.
A destructor.
A constructor.
B constructor.
A destructor.
B destructor.
A destructor.
A constructor.
C constructor.
C destructor.
A destructor.
A constructor.
C constructor.
A destructor.
C destructor.
A destructor.
I am A.
I am A.
I am A.
I am A.
I am A.
I am A.
I don't understand why, although I create B and C objects, the call of the method iAm() call the A's iAm(). The call of B and C iAm() must call the versions of B and C because the constructor are B and C and because I just cast pointers to the vectors, not the elements in the vector.
What I didn't understand about this?
Thanks You.
Your mistake is that you assume that std::vector<B> is compatible with std::vector<A> because B is derived from A. This is not the case. The inheritance relationship between A and B does not translate to an inheritance relationship between std::vector<A> and std::vector<B>. You had to use C-style casts to silence the compiler's error messages, but that doesn't fix the problem.
You might want to check out this question:
Vector that can have 3 different data types C++
Here's an example how your code could work:
std::vector<std::vector<A*>*> vect;
//you can also do vect.resize(3) and then write something like vect[0] = new std::vector<A*>;
vect.push_back(new std::vector<A*>);
vect[0]->push_back(new A());
vect.push_back(new vector<A*>);
vect[1]->push_back(new B());
(*vect[0])[0]->iAm();
(*vect[1])[0]->iAm();
This will print:
A constructor.
A constructor.
B constructor.
"I am A."
"I am B."
Also, consider using smart pointers.
This question already has answers here:
When to use virtual destructors?
(20 answers)
Closed 8 years ago.
I'm trying to figure out the tricks of class inheritance in C++ and I've built a sample project:
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "Class A initialized" << endl;
}
~A()
{
cout << "Class A destructed" << endl;
}
};
class B : public A
{
public:
B()
{
cout << "Class B initialized" << endl;
}
~B()
{
cout << "Class B destructed" << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
cout << "A* a = new A()" << endl;
A* a = new A();
cout << "B* b = new B ()" << endl;
B* b = new B ();
cout << "A* ab = new B()" << endl;
A* ab = new B();
cout << "delete a" << endl;
delete a;
cout << "delete b" << endl;
delete b;
cout << "delete ab" << endl;
delete ab;
int i;
cin >> i;
return 0;
}
The output I get is:
A* a = new A()
Class A initialized
B* b = new B ()
Class A initialized
Class B initialized
A* ab = new B()
Class A initialized
Class B initialized
delete a
Class A destructed
delete b
Class B destructed
Class A destructed
delete ab
Class A destructed
I can understand the behavior of class B as a derived class - first it constructs the base class and then the derived class. When it calls the destructor, it does the work the other way around. Seems logical.
What I can't understand, is the behavior of ab (allocation of B which I put into an A pointer),
why does the constructor act the same as pure B, but the destructor runs only on A?
Thanks.
The compiler calls member functions of the class that correspond to the static type of the pointer. The type of pointer ab is A * so the compiler calls the destructor of class A. If you would declare the destructor as virtual as for example
class A
{
public:
//...
virtual ~A()
{
cout << "Class A destructed" << endl;
}
};
then the compiler would use the table of vitual function pointers. In this case that is in the case of deleting ab the table would contain the pointer that refers to the destructor of the derived class.
As for the constructor then when you use operator new B() then the static type used in the expression is B. So the consttructor of B is called along with the constructor of A as the constructor of the base class.
There is a fundamental difference between constructors and destructors
(or constructors and any other function, for that matter): when
constructing an object, you must specify its exact type, in the source
code. For all other functions (including the destructor), it is
possible to only mention a base, provided certain conditions are met.
One of those conditions is that the function (or the destructor) be
virtual in the base class.
In the case of destructors, there is an additional constraint, because
the destructor is involved in a delete, which in turn requires the
address of the complete object in order to free the memory correctly.
Thus, given A* pA;, an expression like pA->f() will call the
function f in the base class if it is not virtual, but the function
f() in the derive class if it is virtual, and the derived class
overrides it. On the other hand, delete pA; will call the destructor
of the derived class if the destructor in the base is virtual, but is
undefined behavior if pA points to a derived class, and the
destructor in the base is not virtual. There is no question of just
9alling the destructor of the base class; although this might be the
actual behavior in simple cases, the behavior is undefined in all cases.
For this reason, it has often been recommended that if a class is
designed to be used as a base class, the destructor should be either
virtual, or protected. IMHO, it depends on the class: if anyone
misundertands std::exception<> to the point of writing something like:
std::exception<...>* pIter = new std::vector<...>::iterator;
// ...
delete pIter;
there's no hope, and it's not worth the bother of defining a destructor
for std::iterator, just to make it protected (and in pre-C++11, making
it impossible that the derived iterator be a POD).
In this program "A's constructor called " is printing 2 times. My doubt is why "A's constructor called " is not printing with
A b = B::getA();
while getting printed with
A a;
In both the cases we are creating a new object.
Here is my Program:
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor called " << endl; }
};
class B
{
static A a;
public:
B() { cout << "B's constructor called " << endl; }
static A getA() { return a; }
};
A B::a; // definition of a
int main()
{
A a;
A b = B::getA();
return 0;
}
The first constructor is called at program startup, when the static A within B is created.
The second constructor is called within your main when A is allocated on the stack.
There are no more calls to the default A constructor. When you call getA() a copy constructor will be used, which as you have not defined, will be provided by the compiler.
Because getA() calls a copy constructor, which you haven't written, so the default one will be called.
A b = B::getA();
That initialises b using the copy constructor. You're only tracing the default constructor, which isn't used here. If you wanted to trace the copy constructor too, then you'd need to provide one:
A(A const &) { cout << "A's copy constructor called " << endl; }
one contructore is getting called with "static A a" and "A B::a" i.e static initialization of a which is member of class B
during the execution of program in C, C++ all global and static variables initialized first.
#include <iostream>
using namespace std;
class A
{
int n;
public:
A()
{
cout << "Constructor called" << endl;
}
~A()
{
cout << "Destructor called" << endl;
}
};
int main()
{
A a; //Constructor called
A b = a; //Constructor not called
return 0;
}
output:
Constructor called
Destructor called
Destructor called
Constructor is called once while the destructor is called twice
What is happning here? Is this undefined behaviour?
The second line invokes what is called a Copy Constructor. Much like lawyers, if you do not have one, one will be provided for you by the compiler.
It is a special type of converter that is invoked when you initialize a variable with another of the same type.
A b(a)
A b = a
Both of these invoke it.
A(const A& a)
{
cout << "Copy Constructor called" << endl;
//manually copy one object to another
}
Add this code to see it. Wikipedia has more info.
In the snippet
A b = a
you are not calling your constructor, but the generated copy constructor:
class A
{
int n;
public:
A()
{
cout << "Constructor called" << endl;
}
A(const A& rv)
{
cout << "Copy constructor called" << endl;
// If you are not using default copy constructor, you need
// to copy fields by yourself.
this->n = rv.n;
}
~A()
{
cout << "Destructor called" << endl;
}
};
Default Copy Constructor is used to create the second instance.
When you leave the scope the destractor for both objects is called
There are two instances of object A created. One is created by a constructor, the other by the copy constructor. Since you did not explicitly define one, the compiler did the work for you.
Once the app exits, since there are two objects, the destructor method is called twice.
A b=a => A b(a) => This calls the default copy constructor of the class.
#include <iostream>
using namespace std;
class A{
int b;
public:
A(){
cout<<"Constructor for class A called\n";
b = 6;
}
~A(){
cout<"Destructor called for class A\n";
}
};
class B{
A a;
public:
B(){
cout<<"Constructor for class B called\n";
}
~B(){
cout<<"Destructor called for class B\n";
}
};
int main(void){
B obj1;
return 0;
}
When the above code is executed the constructors for both A and B are called as expected but when B's object i.e. obj1 goes out of scope only B's destructor is called. Why A's destructor is not called even though A's obj is one of the members of B ?
You're missing a < in A's destructor:
cout << "Destructor called for class A\n";
If you're not getting a compilation error for the expression:
cout < "Destructor called for class A\n"
|
//less than operator
well, your compiler is trying to compare cout to a const char*. Which is a weird thing to do. But, alas, change < to << and it should work: http://ideone.com/8TDyy
You forgot a < character in the destructor of A.
The line
cout<"Destructor called for class A\n";
just means: compare cout with the given string and return true or false.
You should write
cout<<"Destructor called for class A\n";
And then it works correctly.
It's better to add spaces before and after the << operator to make this clearer (I always say that code needs to breath (it needs some air)).
Your code shows:
cout<"Destructor called for class A\n";
There should be two <<'s, not one. I'm surprised it compiles at all...
~A(){
cout<"Destructor called for class A\n";
}
the operator to be used with cout is << and not < its the less than operator
correct it and your code will be fine.
~A(){
cout<<"Destructor called for class A\n";
}