#include <cstdio>
using namespace std;
class A {
public:
virtual void func() { printf("A::func()"); }
};
class B : public A {
public:
virtual void func() { printf("B::func()"); }
};
int main() {
A a = *(A *)new B();
a.func();
}
The question is simple: why a->func() calls function in class A even though a contains object of class B?
A a = *(A *)new B();
a.func();
Here's what happens in this code, step by step:
new B(): a new object of type B is allocated on the free store, resulting in its address
(A*): the address of the object is cast to A*, so we have a pointer of type A* actually pointing to an object of type B, which is valid. All OK.
A a: here the problems start. A new local object of type A is created on the stack and constructed using the copy constructor A::A(const A&), with the first paremeter being the object created before.
The pointer to the original object of type B is lost after this statement, resulting in a memory leak, since it was allocated on the free store with new.
a.func() - the method is called on the (local) object of class A.
If you change the code to:
A& a = *( A*) new B();
a.func();
then only one object will be constructed, its pointer will be converted to pointer of type A*, then dereferenced and a new reference will be initialized with this address. The call of the virtual function will then be dynamically resolved to B::func().
But remember, that you'd still need to free the object since it was allocated with new:
delete &a;
Which, by the way, will only be correct if A has a virtual destructor, which is required that B::~B() (which luckily is empty here, but it doesn't need to in the general case) will also be called. If A doesn't have a virtual destructor, then you'd need to free it by:
delete (B*)&a;
If you would want to use a pointer, then that's the same as with the reference. Code:
A* a = new B(); // actually you don't need an explicit cast here.
a->func();
delete (B*)a; // or just delete a; if A has a virtual destructor.
Now that you've modified your code snippet, the problem is clear. Polymorphism (i.e. virtual functions) are only invoked via pointers and references. You have neither of these. A a = XXX does not contain an object of type B, it contains an object of type A. You've "sliced away" the B-ness of the object by doing that pointer cast and dereference.
If you do A *a = new B();, then you will get the expected behaviour.
The problem you encounter is classic object slicing :
A a = *(A *)new B();
Make a either a reference or pointer to A, and virtual dispatch will work as you expect. See this other question for more explanations.
You commented on another answer that "Compiler should at least give warning or what". This is why is it considered a good practice to make base classes either abstract of non copyable : your initial code wouldn't have compiled in the first place.
This might do that trick.
A &a = *(A *)new B();
a.func();
Or
A *a = new B();
a->func();
Virtual dispatch works only with pointer or reference types:
#include <cstdio>
using namespace std;
class A {
public:
virtual void func() { printf("A::func()"); }
};
class B : public A {
public:
virtual void func() { printf("B::func()"); }
};
int main() {
A* a = new B();
a->func();
}
The problem is the deference and casting of B to A with the A a = *(A *)new B();
You can fix it with just removing the *(A *) changing it to (A *a = new B(); ) but I would take it a step further since your variable name is not good for instantiation of B.
It should be
B *b = new B();
b->func();
Because you performed slicing when you copied the dynamically allocated object into object a of type A (which also gave you a memory leak).
a should be a reference (A&) instead, or just keep the pointer.
Related
I am trying to write a function that creates a class object from two pointers to other class objects, but I keep getting a read access violation error.
My program has three classes:
class A {
public:
A(const A& a2); // Special copy constructor
private:
int a = 0;
}
class B {
public:
B(const B& b2); // Special copy constructor
private:
int b = 0;
}
class C {
public:
A* aPtr;
B* bPtr;
}
What I am trying to do, is to have a function that takes a pointer to an A object and a B object, and then dereferences these into a C-instance. It is important that the objects themselves get copied since it is for multithreading purposes. The function is for example:
void foo(A* ptrA, B* ptrB){
C* ptrC = new C();
*ptrC->aPtr = *A;
*ptrC->bPtr = *B;
}
But this gives me a read access violation error.
What am I doing wrong? I know that objects themselves get copied without error, so I think it has something to do with how i declare ptrC or dereference ptrC->A and ptrC->B. Am I right about this?
What is a possible solution?
Thanks in advance.
A(const A& a2); // Special copy constructor
What you call a "special copy constructor" is commonly known as a converting constructor.
But this gives me a read access violation error. What am I doing
wrong?
C* ptrC = new C();
This creates a dynamic object and value initialises it. The pointers that are members are value initialised to null.
*ptrC->aPtr = *A;
*ptrC->bPtr = *B;
Here, you indirect through those null pointers and write to the memory. This results in undefined behaviour.
What is a possible solution?
Don't indirect through null pointers. Perhaps storing A and B objects instead of pointers within the C object would fit better to your design?
yes pretty much try:
void foo(A* ptrA, B* ptrB){
C* ptrC = new C();
ptrC->aPtr = ptrA;
ptrC->bPtr = ptrB;
}
instead
(and try to avoid pointers next time they never help you out with anything)
class A
{
public:
A(){ };
~A(){ };
//stuff
};
class B
{
public:
B(A* a){ pA = a;}
~B(){ };
A* pA;
};
int main()
{
A instOfA = A();
B instOfB = B(&instOfA);
return 0;
}
I am unsure as to whether ~B() should delete its pointer data member *pA. I.e.
~B()
{
if(pA!=nullptr) delete pA;
}
My guess is that a deletion is needed because B is allocating it in A* pA.
This is all about the ownership and thereby the question is a design question. You are not dynamically allocating A so I would not let B touch it though. It will be deleted in the end of the main.
If you would allocate an instance of A dynamically (A* instOfA = new A();
), then you could choose if you want to pass the ownership of that instance to B and have B deleting it.
My guess is that a deletion is needed because B is allocating it in A*
pA.
Your guess is not right. B is not allocating A. All it does is to take a pointer of the instance that was allocated in the main.
You're guess is incorrect, since
B instOfB = B(&instOfA);
passes the address of an A of automatic storage duration to Bs constructor. Operator delete can only be safely used to destroy an object that was created with the corresponding operator new. Using operator delete to destroy an object that was NOT created with the corresponding operator new gives undefined behaviour.
instOfA is guaranteed to cease to exist when main() returns, so no action is needed to destroy it. And any action which results in it being destroyed twice (so its destructor is called twice on the same object) also gives undefined behaviour.
Generally speaking, it would often be better to design your class B so it manages the A completely (e.g. manage its lifetime) to ensure consistency. By accepting a pointer, it is not possible to prevent (other than by strident documentation, and relying on programmers heeding the documentation) an object being passed to the constructor that the destructor does not handle correctly.
If you are going to do delete pA, it is not necessary to test that pA is non-NULL. The standard specifies that the delete operator has no effect on a NULL pointer.
I have a doubt about downcasting an object in C++.
Here it comes an example:
class A { }
class B : public A {
public:
void SetVal(int i) { _v = i; }
private:
int _v;
}
A* a = new A();
B* b = dynamic_cast<B*>(a);
b->SetVal(2);
What would it happen with this example? We are modifying a base clase like if it is a child one... how does it work related with the memory?
With this cast... Is it like creating an instance of B and copying the values of A?
Thanks
A* a;
This just gives you a pointer to an A. It doesn't point anywhere in particular. It doesn't point at an A or B object at all. Whether your code works or not depends on the dynamic type of the object it is pointing at.
So there are two situations you might want to know about. First, this one:
A* a = new A();
B* b = dynamic_cast<B*>(a);
b->SetVal(2);
This will give you undefined behaviour because the dynamic_cast will return a null pointer. It returns a null pointer when the dynamic type of the object is really not a B. In this case, the object is an A. You then attempt to dereference the null pointer with b->SetVal(2), so you get undefined behaviour.
A* a = new B();
B* b = dynamic_cast<B*>(a);
b->SetVal(2);
This will work fine because the object really is a B object. The dynamic cast will succeed and the SetVal call will work just fine.
However, note that for this to work, A must be a polymorphic type. For that to be true, it must have at least one virtual member function.
That shouldn't even compile, because the classes aren't polymorphic so you can't use dynamic_cast.
If it did, it would be undefined behavior.
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.
#include "iostream"
class A {
private:
int a;
public :
A(): a(-1) {}
int getA() {
return a;
}
};
class A;
class B : public A {
private:
int b;
public:
B() : b(-1) {}
int getB() {
return b;
}
};
int main() {
std::auto_ptr<A> a = new A();
std::auto_ptr<B> b = dynamic_cast<std::auto_ptr<B> > (a);
return 0;
}
ERROR: cannot dynamic_cast `(&a)->std::auto_ptr<_Tp>::get() const
Well, std::auto_ptr<B> is not derived from std::auto_ptr<A>. But B is derived from A. The auto_ptr does not know about that (it's not that clever). Looks like you want to use a shared ownership pointer. boost::shared_ptr is ideal, it also provides a dynamic_pointer_cast:
boost::shared_ptr<A> a = new A();
boost::shared_ptr<B> b = dynamic_pointer_cast<B> (a);
For auto_ptr, such a thing can't really work. Because ownership will move to b. But if the cast fails, b can't get ownership. It's not clear what to do then to me. You would probably have to say if the cast fails, a will keep having the ownership - which sounds like it will cause serious trouble. Best start using shared_ptr. Both a and b then would point to the same object - but B as a shared_ptr<B> and a as a shared_ptr<A>
dynamic cast doesn't work that way. A : public B does not imply auto_ptr<A> : public auto_ptr<B>. This is why boost's shared_ptr provides shared_dynamic_cast. You could write an auto_ptr dynamic cast though:
template<typename R, typename T>
std::auto_ptr<R> auto_ptr_dynamic_cast(std::auto_ptr<T>& in) {
auto_ptr<R> rv;
R* p;
if( p = dynamic_cast<R*>( in.get() ) ) {
in.release();
rv = p;
}
return rv;
}
Just be aware of what happens here. Since auto_ptrs have ownership semantics, a successful downcast means the original more generally typed, auto_ptr no longer has ownership.
The reason is that auto_ptr is not actually a pointer. It's a smart pointer which is a pointer wrapper but not actually a pointer. The type that is passed as a template style argument to dynamic_cast must be a true pointer (or reference) type.
http://msdn.microsoft.com/en-us/library/cby9kycs(VS.80).aspx
You're trying to cast a A* (returned by a.get()) to std::auto_ptr<B>, and since the second is not even a pointer type this fails. Probably you just want to cast it to B*:
std::auto_ptr<A> a(new A());
std::auto_ptr<B> b(dynamic_cast<B*>(a.get()));
This will still not compile, because A and B aren't polymorphic types. A needs to have a virtual function in order to make the types polymorphic. This will compile, but the cast will just throw std::bad_cast, since it isn't really a B*.
And even if it were a B*, it will fail in horrendous ways if you try to use it. Both std::auto_ptrs a and b will assume they own the object and free it later on, resulting in all kinds of memory corruption. You probably want to use a.release() after the cast was successful.
I think c++ stores RTTI (run time type information) in the vtable. Hence to use dynamic_cast<> with an instance object, the object needs have 'vtable'. C++ creates vtable only when at least one function is declared 'virtual' in the class.
The class A and Class B there are no virtual functions. This could be reason for the dynamic_cast failure. Try declaring a virtual destructor in base class.