C++ unwanted destruction - c++

Can somebody explain why when c finishes construction, the destructor of b (member of c) is called, while d is destructed - as expected - when c's destructor is called ?
#include <iostream>
using namespace std;
class A
{
public:
int a, b;
};
class B
{
public:
A* array[10];
B()
{
for(int i = 0 ; i < 10 ; i++)
array[i] = new A();
}
~B()
{
for(int i = 0 ; i < 10 ; i++)
delete array[i];
}
};
class C
{
public:
B b;
B* d;
C()
{
b = B();
}
~C()
{
delete d;
}
};
int main()
{
B b = B();
C c = C();
cout << "Ashlamish" << endl;
system("pause");
return 0;
}

In b = B() you're constucting a new temporarty instance of class B, assigning a copy to b, then the temporary instance is descructed.

Because in the constructor of C, you are creating a temporary B object in the line c = B(); and when the assignment is complete, that temporary object is being destroyed.

I think you want to declare c like this:
C c;
This will construct an object named c which will be destructed on scope exit.
On the other hand, what you have;
C c = C();
will construct an anonymous object of type C, copy construct c with it and immediately destruct the anonymous object. c will still be destructed at the end of the scope.

In the constructor of C you have
b = B();
what this does is:
construct temporary object of type B
assign this object to b by the use of default assignment operator
destroy the temporary object
To fix this use initialization list in the constructor of C like this:
C() : b()
{ }
or just leave the constructor empty, that way it will use the default constructor.

The line b = B(); in C constructor instantiates a new object of type B, and uses B's copy constructor to copy such object in C::b.
When C constructor returns b doesn't get destroyed, but the B temporary object used to call b's copy constructor is.
You could just remove such instruction in order to avoid instantiation of a B temporary, in this case b will just be constructed using the default constructor.

destructor of temporary B is called (b = B();), not of member b. this line can be removed at all because b is already default constructed in implicit initialization list

You have committed here a cardinal sin - not obeying the rule of 3.
Your B needs a destructor but does not implement copying and assignment.
You then go ahead and compound the error by actually doing an assignment.
You also go on to delete an uninitialised pointer. (It would be fine if d were NULL but there is no reason why it should be).
You also need to implement copy-construction, especially as your compiler may well choose to use it for the above constructs, although it probably won't actually do so.

Related

How to use virtual functions in derived objects without new?

I would like to use virtual functions of objects of different classes (derived from the same base class) without a) constructing all the objects or b) using new. Please see the code example:
#include <iostream>
class A{
public:
virtual void p(void){std::cout << "Im A" << std::endl;};
};
class B : public A{
public:
virtual void p(void) override {std::cout << "Im B" << std::endl;};
};
class C : public A{
public:
virtual void p(void) override {std::cout << "Im C" << std::endl;};
};
int main(){
bool cond = true; // some condition
A* o1;
if (cond) o1 = new B(); else o1 = new C();
o1->p(); // will call correct p(), i.e. either B::p or C::p but not A::p
A o2 = B();
o2.p(); // will call A::p
A* o3;
B tmp1; C tmp2; // construct both objects altough only one is needed
if (cond) o3 = &tmp1; else o3 = &tmp2;
o3->p(); // will call correct p(), i.e. either B::p or C::p but not A::p
A* o4;
if (cond) {B tmp; o4 = &tmp;} else {C tmp; o4 = &tmp;} // uses address of local variable
o4->p(); // will call correct p(), i.e. either B::p or C::p but not A::p
return 0;
}
I want the behavior of o1 but without calling new. o2 doesnt work (calls function of base class and if base class is abstract it doesnt work at all). o3 works but constructs all the different objects although only one is needed. o4 kinda "works" but uses a reference to a local variable outside of its scope.
What would be the correct / best / modern C++ way to do it?
It will be better to use a helper function when you want to avoid using new but be able to use different derived types based on some condition.
void do_stuff(A& obj)
{
}
int main()
{
bool cond = true; // some condition
if (cond)
{
B tmp;
do_stuff(tmp);
}
else
{
C tmp;
do_stuff(tmp);
}
return 0;
}
How to use virtual functions in derived objects without new
Like this:
B b;
C c;
A& a = cond ? b : c;
a.p();
without a) constructing all the objects
You can also do this:
if (cond) {
B b;
b.p();
} else {
C c;
c.p();
}
At this point it doesn't really matter that the function is virtual though since we are using static dispatch. Which is better than dynamic dispatch.
o4 kinda "works" but uses a reference to a local variable outside of its scope.
I.e. the behaviour of the program is undefind i.e. it doesn't work at all.
If using placement new is acceptable, you can use a union to hold the storage, then construct the proper member based on the condition:
union U {
U() { }
B b;
C c;
};
int test(bool cond) {
U u;
A *a2;
if (cond)
a2 = new (&u.b) B;
else
a2 = new (&u.c) C;
a2->p();
return 0;
}
The constructor in the union is necessary since the default constructor will be implicitly deleted due to the presence of non-trivial default constructors for the members of the union.
You'll also have to manually destroy your objects when you're done.
For starters this code snippet
A* o4;
if (cond) {B tmp; o4 = &tmp;} else {C tmp; o4 = &tmp;} // uses address of local variable
o4->p(); // will call correct p(), i.e. either B::p or C::p but not A::p
has undefined behavior because outside the if statement the pointer o4 is invalid due to the fact that the local object tmp is not alive outside the scopes of the if sub-statement.
As for this code snippet
A o2 = B();
o2.p(); // will call A::p
then you should use a reference to an object of the type B. For example
B b;
A &o2 = b;
o2.p();
As for the code snippet with the pointer o1 then in any case pointed objects must exists. Either they will be created dynamically as in your example or you can create the both locally and then depending on the condition set the pointer to one of them.
If you're worried about using new because of memory management, just use a std::shared_ptr instead:
int main(){
bool cond = true; // some condition
std::shared_ptr<A> o1;
if(cond) {
o1 = std::make_shared<B>();
} else {
o1 = std::make_shared<C>();
}
o1->p();
return 0;
}
Prints:
Im B
Working example
Note: I was originally going to suggest an std::unique_ptr instead, however I didn't think they were copyable. But I was wrong. std::unique_ptrs will work too.
Note 2: you will need C++14 or later to use std::make_shared() or std::make_unique, but new will work in C++11. That violates your rule of not using new, but at least it does manage memory for you.
If you want to avoid new mainly to avoid the extra cleanup code and potential bugs from dangling pointers, double deletes, etc., just use std::unique_ptr:
std::unique_ptr<A> o1;
if (cond)
o1 = std::make_unique<B>();
else
o1 = std::make_unique<C>();
o1->p();
This will do essentially the same as the code using new, but behind the scenes, and also does the delete for you when o1 goes out of scope.
If you have a performance-critical code bottleneck and want to avoid the overhead of the heap memory allocation and deallocations used by new, things get trickier, but you could do it with something like:
using B_or_C_type = std::variant<B,C>;
auto o5 = cond ? B_or_C_type{B{}} : B_or_C_type{C{}};;
std::visit(std::mem_fn(&A::p), o5);
On typical systems, this code will avoid using any heap memory at all, instead using stack memory large enough to hold the larger of B or C. std::variant has the logic to act like a union but making sure only the correct type actually gets used. std::visit applies any functor to a variant, as long as the functor can be called with every type in the variant. Note if you define a variant variable with no initializer, it creates an object with the first type, though it can be reassigned to a different-typed object later. (If creating that default object isn't possible or should be avoided, you could use std::monostate as the first dummy type - but then using std::visit gets trickier.)

C++ Constructors With References and Pointers?

I found this example interview question and would like some help understanding it:
#include <iostream>
class A
{
public:
A(int n = 0)
: m_n(n)
{
++m_ctor1_calls;
}
A(const A& a)
: m_n(a.m_n)
{
++m_copy_ctor_calls;
}
public:
static int m_ctor1_calls;
static int m_copy_ctor_calls;
private:
int m_n;
};
int A::m_ctor1_calls = 0;
int A::m_copy_ctor_calls = 0;
void f(const A &a1, const A &a2 = A())
{
}
int main()
{
A a(2), b = 5;
const A c(a), &d = c, e = b;
std::cout << A::m_ctor1_calls << A::m_copy_ctor_calls;
b = d;
A *p = new A(c), *q = &a;
std::cout << A::m_copy_ctor_calls;
delete p;
f(3);
std::cout << A::m_ctor1_calls << A::m_copy_ctor_calls << std::endl;
return 0;
}
The way I understand it, the first line of main creates two new objects, resulting in 2 calls to the constructor. In the second line, I see that they use the copy constructor for c(a) and e = b. The copy constructor isn't used for &d = c because it is only referencing c is that right? Also one thing I don't understand is that if the copy constructor requires a reference, how come an object is being passed into it instead of a reference to the object? The parts after with pointers are really confusing to me. Can someone provide some insight?
Thanks!
The copy constructor isn't used for &d = c because it is only
referencing c is that right?
Yes. d becomes an alias for c.
Also one thing I don't understand is that if the copy constructor
requires a reference, how come an object is being passed into it
instead of a reference to the object?
An object passed into a function taking a reference is automatically "converted" into a reference. The parameter is now an alias for the passed-in object.
The parts after with pointers are really confusing to me. Can someone
provide some insight?
p points to a newly allocated A object, copied from c. q points to a. (1 copy constructor). Then p is deleted.
f(3) gets fun. It constructs a temporary A initialized with 3 to bind to a1. a2 gets a temporary default constructed A. After f(3) finishes, these two temporaries are destroyed.
End of the function, and the remaining instances of A are destroyed.
Outside of an interview, you can stick this code in an IDE and step through it with a debugger.
In case you were wondering, here is the output (with spaces added):
2 2 3 4 3

Why there are no memleaks in the following C++ while assign?

the following code demotes my belief that I know C++ more or less. Why valgrind does not show any memleak here? Why I expect memleaks:
B is larger than A: it contains an additional member; so on assign there should be class' fields slicing.
~A() does not have a virtual dtor. So when we call delete a only ~A() should be called and memory allocated in B would lost.
But I receive that the calling order of dtors is: ~A(), ~B(), ~A(). Why?!
struct A {
~A()
{
std::cerr << "~A" << std::endl;
}
};
struct B : A {
int* data;
B() : data(new int[20]) {}
~B()
{
std::cerr << "~B" << std::endl;
delete [] data;
}
};
main():
A* a = new A;
B* b = new B;
*a = *b;
delete a;
delete b;
UPD:
Shame on me! I muddled deletion of an object by the pointer of base class when virtual dtor should called. Here just contents of class copying. Thanks everyone!
delete a;
a is A*, so A::~A is called
delete b;
b is B* so B::~B is called.
Why would there be a problem?
Class fields' slicing? Yeah, so? You're just copying the A fields from *b to *a, nothing more than that. No memory is lost here.
In *a = *b you are copying (and yes, slicing) *b to *a. However, that leaves *b unchanged; it doesn't get sliced. When you delete b, you are asking for ~B() to be called on *b.
The *a = *b; assignment only copy the common A part of the data (and A has no fields).
You made a delete for each new , so there is no memleak.
*a =*b
does not allocate anything, the copy constructor just copies the part of b which can go to a, but it does not call new..
By invoking *a = *b;, you're implicitly calling the assignment operator function created by the compiler that looks like this:
A &operator=( const A &other ){
}
which in your case doesn't do anything since A has no member variable.
Your class A is empty, so it is entirely irrelevant for the purpose of this discussion. The only code that is involved in dynamic allocation is:
B* b = new B;
delete b;
Since you delete an object created with new, there is no leak. Furthermore, the class B contains sufficient code to clean up its own internal allocation in this straight-forward use-case.
(Note that class B is still horribly broken, since it will not survive copying or assignment. The classic Rule of Three (or Five).)
Because what you do here is object slicing. I think you intended to have the base pointer point to the derived object and since the base destructor is not virtual, derived class destructor not called during cleanup. But that is not the case here.
*a = *b
The compiler will 'slice' those derived part of the object and copy only the base part of the object. This is not usually one want to do because this will result in an incomplete object with only base class properties and specialized derived class properties missing.

c++ inheritance question

I have a question about this:
class A
{
int a;
int* pa;
public:
A(int i):a(i) , pa(new int(a))
{
cout<<"A ctor"<<a<<endl;
}
~A()
{
delete pa;
cout<<"dtor\n";
}
int * &get()
{
return pa;
}
};
class B : public A
{
int b;
public:
B (A obj): A(obj) , b(0)
{
cout<<"B ctor\n";
}
~B()
{
cout<<"B dtor\n";
}
};
int main()
{
int i = 23 ;
A* p = new B(i);
}
Can tell me why the last line in main compiles? I pass an int into B's constructor which expects an A object instead. I believe that the int is translated to an A in B's constructor, but why?
Thanks in advance.
Avri.
Since you have not declared A constructor as explicit compiler is creating an anomymous instance of A using i and using it to initialize B instance. If you don't want the compiler to do these implicit conversions declare your costructor as explicit. Then you will get a compiler error.
Because A has a single parameter constructor which takes an int and isn't marked explicit you can implicitly convert an int to an A.
When you do new B(i), because the only viable constructor for B takes an A, an attempt is made to convert i to an A and construct the new B from that. This conversion is done by creating a temporary A using the constructor that takes an int.
When the B object is constructed, the base class A is copy constructed from the temporary A which means copying the member variables a and pa from the temporary A.
Strictly, because the constructor takes an A object by value, the temporary is, conceptually, copied again. The compiler may, however, eliminate the temporary by constructing the constructor parameter for B directly from i so the effect may well look like just a single copy.
This will cause a serious error because when the temporary A is destroyed, delete pa will cause the dynamically allocated int to be destroyed but the base class A of the newly allocated B object will still have a copy of this pointer which now no longer points at an invalid object. If the compiler doesn't eliminate one of the copies, a "double free" will happen immediately.
The key aspect of A is that it has a user-defined destructor that performs a resource action (deallocation). This is a strong warning that A needs a user-defined copy constructor and copy assignment operator because compiler generated version are likely not to work consistently with the design of A.
This is known as the "rule of three" which says that if you need a user-defined version of one of the destructor, copy constructor or copy assignment operator then you are likely to need user-defined versions of all of them.
Were you to attempt to free the dynamically allocated B object in your example, it would likely cause a "double free" error. In addition, A's destructor would need to be marked as virtual for a delete through a pointer to A to work correctly.
Since there is a conversion from int to A, implicitly your code is translated into
A* p = new B(A(i));

What does object* foo(bar) do?

For some class C:
C* a = new C();
C* b(a); //what does it do?
C* b = a; //is there a difference?
C* b(a) and C* b = a are equivalent. As with many languages, there's more than one way to do it...
Note that in
C* a = new C();
C* b(a);
b is a pointer to a C object assigned the same value as a. However,
#include "somefile.h"
C* b(a);
we could just as easily be defining b as a function which takes an object of type a, and returns a pointer to C.
The standard describes the different kinds of initialization is 8.5, and these two specifically under 8.5/12.
C* b(a); //what does it do?
This is called direct initialization. If 'b' had class type, then the compiler would perform overload resolution on the constructors in C using 'a' as an argument. For a pointer type, it simply initializes 'b' with 'a'.
C* b = a; //is there a difference?
The standard does consider these to be different in some cases, the above syntax is called copy initialization. As for direct initialization as 'b' is not a class type, then it is initialized with the value of 'a'. If 'a' and 'b' are the same class type, then direct initialization is used.
Where 'b' is a class type and 'a' has a different type (class or not) then the rules are slightly different (8.5/14-b1.b3). So for the following code:
C b = a;
Firstly, an attempt is made to convert 'a' to type 'C' and then this temporary object is used to initialize 'b'. This is significant as you can have a situation where direct initialization succeeds but copy initialization fails:
class A {
public:
operator int ();
};
class B {
public:
B (int);
};
void foo ()
{
A a;
B b1 (a); // Succeeds
B b2 = a; // Fails
}
C* a = new C(); Now it is creating a pointer of
type C, which also allocate new
memory by using new keyword....
Following statement is depend upon
your constructor logic. C*
b(a); //what does it do?
Your first and third statement are
equivalent. C* b = a; //is there a
difference?
The first one creates a new instance of C and puts its address in a.
The second one is a pointer-to-function declaration. This pointer can point to any function taking an argument of type a and returns a pointer to an object of type C.
The third one declares b, a pointer to an object of type C and initializes it with a.