When a class is instantiated, a virtual table pointer is created to point to its virtual table. And each virtual function is assigned a function address.
Will the pure virtual function be assigned a default function address?
class base {
public:
virtual void func() = 0;
};
class derived : public base {
public:
virtual void func() {
cout << "derived func" << endl;
}
};
int main()
{
base *ptr = new derived();
delete ptr;
ptr->func();
return 0;
}
I have run the demo on VS2017 and the error "performed a bad memory access" happened.
I know that the "__cxa_pure_virtual" will be called under the Linux system. So how do I implement my "__cxa_pure_virtual"? And how can I assign the function address to my pure function?
Calling a method in a deleted object is undefined behaviour, so in principle anything can happen and it’s your fault, but we can explain why you saw this behaviour.
First when you have a pure virtual function, the compiler could store a null pointer into the vtable, and when you call the function it crashes. Your compiler is helpful, it stores a pointer to a function named __cxa_pure_virtual, which is designed to crash when you call it. So a crash in this function tells you the crash was due to calling a pure virtual function. This is both more convenient for debugging, and it is safer to have a defined crash.
Second you deleted ptr. Deleting a derived object runs the derived class destructor, then it turns the object into a base class object, then it calls the base class destructor. Ptr had a pointer for a real func() in its vtable, but the csecond of these three steps replaced it with a pointer to __cxa_pure_virtual. It seems the memory for the object was released but not overwritten so your code manages to call the pure virtual function.
And you absolutely one hundred percent cannot implement __cxa_pure_virtual. It is already implemented. It crashes when called and that is intentional and how it should be.
Following a pointer to a deleted object is undefined behaviour.
Sometimes it will work, sometimes it will crash, sometimes it will format your hard drive.
In a typical implementation in machine code, deleted objects have their memory marked be recycled, This marking may or may not modify the data inside where the object was. At some poimt, another allocation will reuse that memory.
The vtable pointer is stored near the front of the object, and can be overwritten at any point. Or maybe not overwritten. Maybe it gets a pointer to a different vtable, which has a delete directory function there. Or maybe thr compiler does whole program optimization and proves every valid pointer to base is a pointer to derived, and devirtualizes every call.
Related
The code is pretty straight forward:
class SuperClass
{
public:
virtual void someMethod() = 0;
};
class SubClass : public SuperClass
{
public:
virtual void someMethod()
{
std::cout << "hello" << std::endl;
}
};
class CallerClass
{
public:
std::vector<SuperClass*> subClasses;
CallerClass()
{
subClasses.push_back(&SubClass());
}
void callMethods()
{
subClasses[0]->someMethod();
}
};
int main(int argx, char**argv)
{
CallerClass cc;
cc.callMethods();
return 0;
}
The problem occurs when I actually call try to call the subClass' 'someMethod()' in the CallerClass' 'callMethods()'. In Visual Studio, it simply breaks at that line of code without any explanation. I have solved the problem by changing push_back(&SubClass()) to push_back(new SubClass()).
I am curious as to why the latter works and not the former. I thought it was because an object created in a method will only exist within the method, and by using 'new', space was actually being allocated for that object after the function ended; but I added an int a = 1 to SuperClass and was able to access it using in a similar fashion to what's inside 'callMethods()'.
I must be missing some fundamental aspect of C++ here. Please inform me. Hopefully it's not something too obvious.
In
subClasses.push_back(&SubClass());
You are storing a pointer to a temporary object, which is destroyed just after.
Then, when you call someMethod, you are calling a method on an invalid object pointer which was already deleted.
With
subClasses.push_back(new SubClass());
You are storing a pointer to a valid object, so it works.
Yes, if you do push_back(&SubClass()) you are adding a pointer to the vector that points to a temporary object. At the end of the expression the temporary object will be deleted. When you call callMethods you are dereferencing a pointer to a deleted object. This is undefined behaviour, anything could happen, it could even work!
By calling push_back(new SubClass()); you are allocating an object on the heap and adding a pointer to that object to the vector. This object on the heap will not be deleted when the expression ends.
In fact this object will not be deleted at all and would be a memory leak in your program. CallerClass effectively owns the objects so it is its responsibility to delete them when it is done.
To fix the memory leak there are a couple of changes you need to make. You need to add a public virtual destructor to SuperClass:
virtual ~SuperClass(){};
This ensures that if you call the destructor on SuperClass the SubClass will also be destroyed properly. Then you need to ensure that delete is called in the CallerClass destructor. You could do that by explicitly writing a destructor, looping over the elements of the vector and calling delete but the easier, C++11 way, is to use smart pointers like std::unique_ptr. If you change your vector to:
std::vector<std::unique_ptr<SuperClass>> subClasses;
then the objects will be automatically deleted in the CallerClass destructor and you don't have to explicitly write a destructor at all.
Live Demo
Having class A, for example,
class A{
public:
int x;
void Update(){
cout << " from a\n";
}
};
In order to instantiate an object of A without calling the constructor, it goes like:
A* a = (A*) new char[sizeof(A)];
a->x = 9;
cout << a->x; a->Update(); //"9 from a" is outputted
now In case Update is a virtual function
class A{
public:
int x;
virtual void Update(){
cout << " from a\n";
}
};
It throw an "Access violation" exception, why ?
When a class declares one or more virtual functions, the compiler implicitly adds a V-Table pointer to the class declaration, and thereby, to each object.
For every virtual-function-call, the compiler generates code which reads the function's address from the object's V-Table pointer, and then jumps to that address.
The V-Table pointer of an object is initialized only during runtime, when the constructor of the class is called and the object is created.
So when you create an object without explicitly calling the object's class-constructor, the V-Table pointer of that object is not initialized.
Then, when you call a virtual function of that object, the CPU attempts to read the function's address from the object's V-Table pointer, and a memory access violation occurs.
Calling a virtual function involves dereferencing the virtual function table pointer, stored within the object. It is dereferencing the place in memory where this value is supposed to be, but of course, it's uninitialized garbage, hence the error.
From the context of the question, it looks to me like you might be interested in Placement new. Placement new will allow you to re-use heap memory that has already been allocated, but will properly initialize the vtable pointer.
If you don't call the constructor of the object, then the virtual method table is not initialized. Therefore you can't expect calling a virtual function call to work. What are you trying to do in the first place >
Casting from an array of bytes into an object is only valid for POD types, that is, types that comply:
No user-defined destructor, constructor or copy operator.
Only public member variables.
No base classes.
No virtual functions.
No member variables of non-POD type, recursively.
That is, your first example is a POD, but your second one is not.
So your cast is valid for the first but not for the second. In the second case you will need to call placement new to construct a proper A object:
char *bytes = new char[sizeof(A)];
A *a= new (bytes) A;
And then, it is your responsibility to call the destructor when you are finished with it:
a->~A();
What are you expecting? Writing silly code results in silly results.
Anyway the objects need a virtual table - see What are you expecting? Writing silly code results in silly results. This table is not being initialised in the code supplied
See http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/
I'm not quite sure I understand virtual destructors and the concept of allocating space on the heap right. Let's look at the following example:
class Base
{
public:
int a;
};
class Derived : public Base
{
public:
int b;
};
I imagine that if I do something like this
Base *o = new Derived;
that 8 Bytes (or whatever two integers need on the system) are allocated on the heap, which looks then something like this:
... | a | b | ...
Now if I do this:
delete o;
How does 'delete' know, which type o is in reality in order to remove everything from the heap? I'd imagine that it has to assume that it is of type Base and therefore only deletes a from the heap (since it can't be sure whether b belongs to the object o):
... | b | ...
b would then remain on the heap and be unaccessible.
Does the following:
Base *o = new Derived;
delete o;
truly provoke memory leaks and do I need a virtual destructor here? Or does delete know that o is actually of the Derived class, not of the Base class? And if so, how does that work?
Thanks guys. :)
You're making a lot of assumptions about the implementation, which may
or may not hold. In a delete expression, the dynamic type must be the
same as the static type, unless the static type has a virtual
destructor. Otherwise, it is undefined behavior. Period. That's
really all you have to know—I've used with implementations where
it would crash otherwise, at least in certain cases; and I've used
implementations where doing this would corrupt the free space arena, so
that the code would crash sometime later, in a totally unrelated piece
of code. (For the record, VC++ and g++ both fall in the second case, at
least when compiled with the usual options for released code.)
Firstly, the classes you declared in your example have trivial internal structure. From purely practical point of view, in order to destroy object of such classes properly the run-time code does not need to know the actual type of the object being deleted. All it needs to know is the proper size of the memory block to be deallocated. This is actually something that is already achieved by C-style library functions like malloc and free. As you probably know, free implicitly "knows" how much memory to deallocate. Your example above does not involve anything in addition to of that. In other words, your example above is not elaborate enough to truly illustrate anything C++-specific.
However, formally the behavior of your examples is undefined, since virtual destructor is formally required by C++ language for polymorphic deletion regardless of how trivial the internal structure of the class is. So, your "how delete knows..." question simply does not apply. Your code is broken. It does not work.
Secondly, the actual tangible C++-specific effects begin to appear when you begin to require non-trivial destruction for your classes: either by defining an explicit body for the destructor or by adding non-trivial member subobjects to your class. For example, if you add a std::vector member to your derived class, the destructor of the derived class will become responsible for (implicit) destruction of that subobject. And in order for that to work, you will have to declare you destructors virtual. A proper virtual destructor is called through the same mechanism as any other virtual function is called. That's basically the answer to your question: the run-time code does not care about the actual type of the object simply because the ordinary virtual dispatch mechanism will ensure that the proper destructor is called (just like it works with any other virtual function).
Thirdly, another significant effect of virtual destruction appears when you define dedicated operator delete functions for your classes. The language specification requires that the proper operator delete function is selected as if it is looked up from inside the destructor of the class being deleted. And many implementations implement this requirement literally: they actually implicitly call operator delete from inside the class destructor. In order for that mechanism to work properly, the destructor has to be virtual.
Fourthly, a part of your question seems to suggest that you believe that failing to define a virtual destructor will lead to "memory leaks". This a popular, but completely incorrect and totally useless urban legend, perpetuated by low-quality sources. Performing polymorphic deletion on a class that has no virtual destructor leads to undefined behavior and to completely unpredictable devastating consequences, not to some "memory leaks". "Memory leaks" are not the issue in such cases.
There is no problem in the size of the object being deleted - it is known. The problem solved by virtual destructors can be demonstrated as follows:
class Base
{
public:
Base() { x = new char[1]; }
/*virtual*/ ~Base() { delete [] x; }
private:
char* x;
};
class Derived : public Base
{
public:
Derived() { y = new char[1]; }
~Derived() { delete [] y;}
private:
char* y;
};
Then having:
Derived* d = new Derived();
Base* b = new Derived();
delete d; // OK
delete b; // will only call Base::~Base, and not Derived::~Derived
The second delete will not finalize the object properly. If the virtual keyword was uncommented, then the second delete statement will behave as expected, and it will call Derived::~Derived along with Base::~Base.
As pointed out in the comments, to be strict, the second delete yields an undefined behavior, but it's used here only for the sake of making the point about virtual destructors.
I have an issue with a memory leak. I have a base-class pointer. From it, I use new to allocate different derived classes. Then, when I try to delete those classes with the reference (not typecasted), I get a memory leak. I researched the problem and found that I should add a virtual destructor to the base-class, but I tried this and I still have a memory leak; that is, according to my task-manager, the memory usage continues to rise with each allocation and deletion of the derived class using the base-class pointer. I tried making it an abstract destructor and added destructors to the derived classes, but I got an undefined reference error. I also tried typecasting the pointer as a derived-class pointer for the delete, but apparently this crashes the program.
Does anyone have any idea what I should do?
Example code:
class A {
public:
A();
~A() {};
virtual ~A(); /*or*/
virtual ~A()=0; /*or*/
/*or nothing?*/
}
class B: private A {
public:
B();
~B() {}; /*this?*/
/*or nothing?*/
}
How sure are you that there really is a memory leak? Normally, the task manager won't be much help here, since it cannot tell how much of the memory belonging to your process is actually allocated. Even memory that is freed still belongs to your process, and may be used at later times by the memory management (normally malloc-like system library).
Use a tool such as mallocdebug, valgrind, purify etc. to find out if there's really a memory leak. These tools will replace the malloc implementation by a new one that keeps track of allocated memory and reports memory that is not freed upon process termination.
Note: On most systems, memory that is freed from a process is not returned to the system before the process exits. It is availabe for new allocations from within the same process, though.
use virtual ~A();
I'd be surprised if virtual ~A()=0 is allowed.
With this code:
A* base = new B();
delete base;
the destructor for B then A will be called.
If you're really still leaking memory, then you have another leak elsewhere.
If you have a virtual destructor, the destructor(s) of your subclass(es) will all be called. no need to do any esoteric magic with abstract deconstructors or anything.
I would assume the memory leak is somewhere inside your object. Maybe you're calling new() on something in B's (or A's?) constructor, but you don't delete it. Without seeing more code, all I can say is "your destructor setup is fine".
You can use:
virtual ~A(){}
or
virtual ~A()=0;
// as long as there is also:
A::~A(){} // inline in the header file or non-inline in the cpp file.
This means that:
A* base;
...
delete base;
will call all the destructors of the derived classes in the correct order.
Note that a pure virtual destructor: virtual ~A()=0; can be useful if you need to have an abstract base class when no other member functions are pure virtual.
It says that if there is a virtual function, it is a good practice to have a virtual destructor. However, if the object is created on the stack but not on heap, do we still need to do that?
Regards,
Strictly speaking no - the virtual destructor is only necessary if the object will be destroyed via a pointer to reference to a base object.
If the static type at destruction time is the actual type of the object, then the correct dtor will be called regardless of whether it's virtual or not.
But if a class has virtual functions, the reason for that is generally so that it can be accessed through a pointer or reference to one of the objects bases. If the object is going to be destroyed through that mechanism, then having a virtual dtor will ensure the correct one is called. And if you have a virtual function, making the dtor virtual comes at next to no cost.
Yes since someone else could write new code that creates your object on the heap. It would be bad practice for your class to assume that it is always going to be created on the stack...
If you write an object with a virtual method, it is expected that you will use it through an interface/base object.
And it is half-expected you will own this object through a pointer (or a smart pointer). In that last case, you need the virtual destructor.
As most of the time, your code will be used by others, you can't predict they won't use the object through its base pointer... In fact, one day, you will perhaps use it this way, too...
Now, in your case, your object is created on the stack, which means that the compiler knows its type statically. Thus, when the object will be destroyed, the right destructor will be called directly, causing zero overhead.
Conclusion: As you said, it's simple good practice, and considering the limited (or zero) cost of a virtual destructor in most cases, it should be upheld.
Simple rule:
Provide either a public virtual destructor or a protected non-virtual destructor for each class that has virtual methods.
If instances of your class are meant to be deleted through a pointer to the base then the destructor must be virtual. If you class is not meant to be deleted through base pointers then making the destructor protected will block external code from deleting through a base pointer.
Note that you can use polymorphic behavior without deleting through base pointers: when you pass the object by reference or pointer but the lifetime is handled always at the most derived type, or using constructs like shared_ptr:
class base {
protected:
~base() {}
virtual void f();
};
class derived : public base {
public:
void f();
};
int main()
{
shared_ptr<base> sp( new derived );
base *b = new derived;
//delete b; // compile time error: cannot access ~base
// if it was allowed it would be UB
delete static_cast<derived*>(b); // correct (static_cast is ok, we know the type)
} // sp goes out of scope: delete at ´derived´ level
One of the aims of OOP is code-reuse. So while you may be allocating objects on the stack at present, that may not always be the case under re-use and maintenance or in a team development environment.
It is generally a trivial overhead that significantly increases the utility, reusability and safety of your code.