What is the explanation behind the answer to this C++ quiz? - c++

I had this question (beginner C++) in a C++ quiz : My answer was incorrect, I want to understand the explanation behind the correct answer - "Undefined behavior"
Question:
What will happen in the following code after the function foo() returns?
class base
{
public:
base() { }
~base() { }
};
class derived : public base
{
private:
int *p_pi_values;
public:
derived() : p_pi_values(new int[100]) { }
~derived() { delete [] p_pi_values; }
};
void foo(void)
{
derived *p_derived = new derived();
base *p_base = p_derived;
// Do some other stuff here.
delete p_base;
}
I gave this answer which turned out wrong ==> integer array will not be properly deleted.
Correct Answer ==> The behavior is undefined.

The destructor of your base class isn't virtual. It's simply a rule of the language that if you delete an object through a pointer to a base subobject, the corresponding base class must have a virtual des­truc­tor, or otherwise it is undefined behaviour.
(In practice, if your base class doesn't have a virtual destructor, the compiler may not emit the necessary code to perform all the necessary clean-up for the derived object. It will just assume that your object is of the same type as the pointer and not bother to look further, as indeed the polymorphic lookup of the most derived object comes at a cost that you don't want to impose needlessly.)
§5.3.5/3:
In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined

You should make your destructor virtual in a base class. The problem with the code as it is now is that delete p_base will cause a destructor of base class to be called. The one from the derived class won't be called and the memory allocated for the array of integers won't be freed.
This happens because if a method isn't virtual in a base class, compiler simply looks at a pointer type and calls a method located in this type (in this case - it's a base class) i.e. a decision what method to call is made during compilation time based on the type of the pointer and not the real type of the object the pointer is referring to.

Out of curiousity I check the C++ specs. The answer to the question is item 3 in section 5.3.5:
In the first alternative (delete object), if the static type of the
object to be deleted is different from its dynamic type, the static
type shall be a base class of the dynamic type of the object to be
deleted and the static type shall have a virtual destructor or the
behavior is undefined.
Personally, I would have answered the same way you did. If you ignore the compiler's warning, the most likely outcome is that the destructor of the derived class won't get called.

I guess compiler is allowed to optimize this code and hence the assignment of p_derived to p_base never happens.
To be more specific the compiler may optimize the code to one line.
delete new derived();
Hence it is viewed that the behavior as undefined as this can change how the compiler really optimizes the code.

Related

What do Clang and GCC do when `delete`ing base classes with non-virtual destructors?

There is already a question asking about the "real-world" behavior of deleteing a pointer to a base class that lacks a virtual destructor, but the question is restricted to a very limited case (the derived class has no members with non-trivial destructors), and the accepted answer just says there's no way to know without checking the behavior of every compiler.
....but that isn't actually very helpful; knowing that every compiler might behave differently doesn't tell us anything about the behavior of any particular compiler. So, what do Clang and G++ do in this case? I would assume they would simply call the base-class destructor, then deallocate the memory (for the entire derived class). Is this the case?
Or, if it's not possible to determine this for all versions of GCC and Clang, how about GCC 4.9 and 5.1, and Clang 3.5 through 3.7?
First, the standard disclaimer: this is undefined behavior, so even with one specific compiler, changing the compiler flags, the day of the week, or the way you look at the computer could change the behavior.
The following all assumes you have some sort of at least slightly non-trivial destruction happening in your destructors (e.g., the objects delete some memory, or contain object others that themselves delete some memory).
In the simple case (single inheritance) you typically get something roughly equivalent to static binding--that is, if you destroy a derived object via a pointer to a base object, only the base constructor is invoked so the object isn't destroyed properly.
If you use multiple inheritance, and you destroy an object of derived class via the "first" base class, it'll typically be about the same as if you used single inheritance--the base class destructor will be invoked, but the derived class destructor won't be.
If you have multiple inheritance and destroy a derived object via a pointer to the second (or subsequent) base class, your program will typically crash. With multiple inheritance, you have multiple base class objects at multiple offsets in the derived object.
In the typical case, the first base class will be at the beginning of the derived object, so using the address of derived as a pointer to the first base class object works about the same as in the single inheritance case--we get the equivalent of static binding/static dispatch.
If we try this with any of the other base classes, a pointer to the derived doesn't point to an object of that base class. The pointer needs to be adjusted to point to the second (or subsequent) base class before it can be used as a pointer to that type of object at all.
With a non-virtual destructor, what'll typically happen is that the code will basically take that address of that first base class object, do roughly the equivalent of a reinterpret_cast on it, and try to use that memory as if it were an object of the base class specified by the pointer (e.g., base2). For example, let's assume base2 has a pointer at offset 14, and base2's destructor attempts to delete a block of memory it points at. With a non-virtual destructor, it'll probably receive a pointer to the base1 subject--but it'll still look at offset 14 from there, and try to treat that as a pointer, and pass it to delete. It could be that base1 contains a pointer at that offset, and it's actually pointing at some dynamically allocated memory, in which case this might actually appear to succeed. Then again, it could also be that it's something entirely different, and the program dies with an error message about (for example) attempting to free an invalid pointer.
It's also possible that base1 is smaller that 14 bytes in size, so this ends up actually manipulating (say) offset 4 in base2.
Bottom line: for a case like this, things get really ugly in a hurry. The very best you can hope for is that the program dies quickly and loudly.
Just for kicks, quick demo code:
#include <iostream>
#include <string>
#include <vector>
class base{
char *data;
std::string s;
std::vector<int> v;
public:
base() { data = new char; v.push_back(1); s.push_back('a'); }
~base() { std::cout << "~base\n"; delete data; }
};
class base2 {
char *data2;
public:
base2() : data2(new char) {}
~base2() { std::cout << "~base2\n"; delete data2; }
};
class derived : public base, public base2 {
char *more_data;
public:
derived() : more_data(new char) {}
~derived() { std::cout << "~derived\n"; delete more_data; }
};
int main() {
base2 *b = new derived;
delete b;
}
g++/Linux: Segmentation fault
clang/Linux: Segmentation fault
VC++/Windows: Popup: "foo.exe has stopped working" "A problem caused the program to stop working correctly. Please close the program."
If we change the pointer to base instead of base2, we get ~base from all the compilers (and if we derive only from one base class, and use a pointer to that base class, we get the same: only that base class' destructor runs).
If you delete an object without a virtual destructor, the compiler will probably assume that the deleted address is the address of the most derived object.
Unless you use a primary base class to delete the object, this won't be the case, so the compiler will call operator delete with an incorrect address.
Of course the compiler will not call the destructor of the derived class, or operator delete of the derived class (if there is one).

Can I delete a union component without checking whether it stores that object?

I mean the following. I have a few classes which inherit the same base class. Union consists of pointers of these classes:
#include "stdio.h"
class A {
public:
A() { printf("A\n"); }
virtual ~A() { printf("~A\n"); }
};
class B : public A {
public:
B() { printf("B\n"); }
virtual ~B() { printf("~B\n"); }
};
class C : public A {
public:
C() { printf("C\n"); }
virtual ~C() { printf("~C\n"); }
};
int main() {
union {
B* b;
C* c;
} choice;
choice.b = new B();
delete choice.c; //We have B object, but deleting C
return 0;
}
It seems to work, but I'm not sure if it isn't implementation-specific behaviour. Can I use such weird deleting method or should I remember a type of stored object and delete it respectively?
P.S. I use C++11 and want it works on both GCC and Visual C++ (2012 and higher). In a real project I have more complex class hierarchy but all of them are successors (directly or indirectly) of the same abstract base class
This is a double dose of undefined behavior. First, you can't delete a B through a pointer to C. §5.3.5 [expr.delete]/p3:
In the first alternative (delete object), if the static type of the
object to be deleted is different from its dynamic type, the static
type shall be a base class of the dynamic type of the object to be
deleted and the static type shall have a virtual destructor or the
behavior is undefined. In the second alternative (delete array) if the
dynamic type of the object to be deleted differs from its static type,
the behavior is undefined.
Second, accessing the inactive member of a union is also undefined behavior in C++.
There's no need to use an union here anyway. B and C share the same base class, so you can just store the pointer in an A *.
You shouldn't. You are only allowed to read from the union member you last wrote into and you're only allowed to delete an object through a pointer to a base class (if it has a virtual destructor). It may seem to work now, but you may find it to break randomly in the future, usually due to an aggressive optimizer.
Why don't you store a pointer to A instead of the union?
As it has been said in other answer, this is not proper C++.
My impression is that you want to keep an union of pointers because in certain circumstances you need an instance of a (sub)class of B, and in another an instance of C, with the issue of B and C having not quite the same interface. Perhaps you store several of these in a container, or simply you don't know until runtime which instance will be used.
So you may keep your code as it was, with perhaps a type tag somewhere indicating which instance has been created, and then use a switch each time you need to determine the correct code to run, or you could leverage your classes to actually invoke the proper function at run time, by including in the common base class of B and C(1) a virtual method, and overload this method in B and C with the proper branch of the switch, then replace the union with a simple pointer to the base class.
(1) that base class doesn't have to be A: if you don't want to clutter your class tree, just make a different class having the minimal interface needed there, and thanks to C++ multiple inheritance, have B and C inherit from it as well. Don't forget the virtual destructor!
For me this case looks legit and there is no undefined behaviour.
He is using type-punning and it is legit because it B* b and C* c in union members is a pointers and could be converted to char array.
Both B and C have virtual destructor because of base class (not because base is a same! but because base have virtual destructor).
12.4.9 If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.
While destructor call, (because it is virtual) exact function address will be picked up from choice variable and proper destructor sequence will be called. So there is no ANY undefined behaviour at all.

Virtual destructor: is it required in base class if base class allocated memory dynamically?

This question looks like the discussion in Virtual destructor: is it required when not dynamically allocated memory?
In an exam question, I have been asked:
- What should any base class that maintain pointers to dynamically allocated memory define?
I answered:
- A copy constructor and an assignment operator (to make sure NOT only pointers are copied... c.f. deep copy), and a destructor (to free allocated memory)
They said this is not correct because this base class should also define a virtual destructor instead of the plain destructor. Why?
If your class is intended to be used polymorphically, you'll likely have pointers to the base class that point to derived objects.
Deleting a derived object through a pointer to a base class with no virtual destructor causes undefined behavior. That's probably her reasoning.
5.3.5
3) In the first alternative (delete object ), if the static type of
the operand is different from its dynamic type, the static type shall
be a base class of the operand’s dynamic type and the static type
shall have a virtual destructor or the behavior is undefined. [...]
Your base class needs a virtual destructor if objects of derived classes are intended to be destroyed via a base-class pointer, like so
Base *pointer_to_base_class = new Derived;
delete pointer_to_base_class;
From your question, it is unclear whether this is the case. Perhaps another part of the question (or a previous question) made clear that such polymorphic destruction was intended. Or, perhaps you were taught during the class to always anticipate such use as a best practice.
They are not 100% correct. Virtual destructor is a must if
class hierarchy used with dynamic polymorphism AND
derived objects are destroyed via pointer to base.
Otherwise non-virtual destructor is OK. But in most cases even if only #1 is intended it's a good style to make destructor virtual regardless of #2.
Within the standard, most inheritance hierarchies have a virtual destructor at their base; however, sub_match is defined to public inherit from std::pair<BidirectionalIterator, BidirectionalIterator> and as such it could own dynamically allocated memory. In a related area, match_results is not required to but usually implemented to public inherit from std::vector<...> which definitely allocates memory.
Your examiner is not entirely incorrect, but the focus on dynamically allocated memory is a red herring and betrays a worrying ignorance of the standard; while in most implementations deleting a derived type by a pointer to base type without virtual destructor will result in destructing a sliced object, per the standard it is undefined behaviour.
Adding to the other answers: You could also envisage a situation where you do want a common base class, but you don't have any actual interface functions for it. But if you want RTTI and dynamic cast support, you need a virtual function in your class. A destructor can be just that function.
For example, imagine you're a recovering Java programmer and insist that everything is an Object. You might start your first C++ program like so:
class Object
{
public:
virtual ~Object() { }
};
Now Object can indeed serve as the ultimate polymorphic base class of each of your classes.
If you also think that Object should be abstract, you can even make the destructor pure-virtual:
class Object { public: virtual ~Object() = 0; }; Object::~Object() { }
To follow up with all good answers here this is good practice to declare a virtual destructor to ensure a proper clean-up when a class is supposed to be subclassed to form a hierarchy and you want to delete the derived object through a pointer to it. The C++ standard is clear on this:
when you want to delete a derived class object through a base class
pointer and the destructor of the base class is not virtual and the
result is undefined
By undefined behavior you could think of memory leaks for example if your derived class allocate some dynamic memories and you try to delete it later on through this base class. Your teacher was probably thinking of this scenario.

What is default destructor if a class inherits from a pure base class?

Considering next two classes :
struct Base
{
virtual ~Base()
{
}
virtual void foo() = 0;
};
struct Derived : public Base
{
virtual void foo()
{
}
};
Is the following causing an undefined behaviour :
Base *obj = new Derived;
delete obj;
?
Additional question : how come that one a method is declared virtual, it is virtual in derived classes (even if the virtual keyword is not used in the derived class), but it is not true for destructors?
Is the following causing an undefined behaviour :
No, that is not invoking undefined behaviour precisely because the destructor of Base is virtual.
EDIT: Its just to clarify a doubt (raised in the following comment), and to emphasize what I said above.
#Oli Charlesworth commented:
Technically, even if it were not declared virtual, the behaviour would not be undefined, it would just be undesirable.
No. The behavior would be undefined.
The section §5.3.5/3 from the Standard says,
In the first alternative (delete
object), if the static type of the
operand is different from its dynamic
type, the static type shall be a base
class of the operand’s dynamic type
and the static type shall have a
virtual destructor or the behavior
is undefined. In the second alternative (delete array) if the dynamic type of the
object to be deleted differs from its static type, the behavior is undefined.
I think it helps removing the doubt.:-)
That is not undefined behaviour. You've declared the base-class destructor as virtual, so at runtime, delete obj will first invoke the "default" destructor in Derived (as you haven't explicitly declared one), and then the destructor in Base.
Since you have declared the base class's destructor as virtual, there is no undefined behavior here.
The statments :
Base *obj = new Derived;
delete obj;
will lead to call the derived class's desctructor and then the Base class's destructor. I didn't get the second question though
For any class, constructors and destructors aren't inherited. This is specified in the standard. As such, your code won't cause undefined behaviour, as it will invoke the default constructor/destructor for the class.
It is for this reason that inheritence doesn't hold true for destructors/constructors. It doesn't make sense for a constructor/destructor to be inherited from a parent object, as this object could potentially have all forms of different members.

Virtual destructors for interfaces

Do interfaces need a virtual destructor, or is the auto-generated one fine? For example, which of the following two code snippets is best, and why? Please note that these are the WHOLE class. There are no other methods, variables, etc. In Java-speak, this is an "interface".
class Base
{
public:
virtual void foo() = 0;
virtual ~Base() {}
};
OR...
class Base
{
public:
virtual void foo() = 0;
~Base() {} // This line can be omitted, but included for clarity.
};
EDIT DUE TO "NOT WHAT I'M LOOKING FOR" ANSWERS:
Exactly what are the consequences of each route. Please don't give vague answers like "it won't be destructed properly". Please tell me exactly what will happen. I'm a bit of an assembly nerd.
Edit 2:
I am well aware that the "virtual" tag means that the destructor won't get called if deleted through a pointer to derived, but (I think) this question ultimately boils down to "is it safe to omit that destructor, for is it truly trivial?"
EDIT 3:
My second edit is just plain wrong and disinformation. Please read the comments by actual smart people for more info.
Consider the following case:
Base *Var = new Derived();
delete Var;
You need the virtual destructor, otherwise when you delete Var, the derived class' destructor will never be called.
If you delete a derived class object via a base class pointer in C++, the result is undefined behaviour. UB is something you really want to avoid, so you must give base classes a virtual destructor. To quote from the C++ Standard, section 5.3.5:
if the static type of the operand is
different from its dynamic type, the
static type shall be a base class of
the operand’s dynamic type and the
static type shall have a virtual
destructor or the behavior is
undefined.
You should use a virtual destructor if you expect people to try to delete objects of a derived class via pointers or references of the parent class. If this is the case, then without a virtual destructor, the derived class will never be properly destructed.
For example,
Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;
Without a virtual destructor in Base, Derived's destructor will never be called, and important stuff will therefore never happen.
Replying mostly to the edit:
Nobody can tell you what will happen because the result is "undefined behavior". When you delete a derived class through a pointer to a base that has no virtual destructor, the implementation is free to break down in any number of ways.
In general, a destructor should be either (1) public and virtual, or (2) protected and non-virtual.
Assuming you never expect anyone to delete a class instance via an interface pointer, a protected non-virtual destructor is 100% safe.
If someone tries to delete an interface pointer in case (2), they'll get a compile-time error.
No... virtual destructors are not auto generated. You have to declare them explicitely in your base class.
But you won't need to declare your destructors virtual for the child classes of Base. This is done by the compiler.
The compiler will also make sure that the destructors are called in reversed order of construction (from derived to base).
public class Base
{
//...
}
public class Derived
{
int i = 0;
//...
}
//...
Base* b = new Derived();
If you didn't have a virtual destructor
delete b;
would cause memory leaks (at least 4 bytes for the integer field), because it would destruct only Base and not Derived. The virtuality makes sure that the derived classes are destroyed, too. You won't have to declare a virtual constructor in Derived, this will be inferred by the compiler, if you declared a virtual destructor in Base.