In the following code:
class A {
};
class B : public A {
};
class C : public A {
int x;
};
int main (int argc, char** argv) {
A* b = new B();
A* c = new C();
//in both cases, only ~A() is called, not ~B() or ~C()
delete b; //is this ok?
delete c; //does this line leak memory?
return 0;
}
When calling delete on a class with a non-virtual destructor with member functions (like class C), can the memory allocator tell what the proper size of the object is? If not, is memory leaked?
Secondly, if the class has no member functions, and no explicit destructor behaviour (like class B), is everything ok?
I ask this because I wanted to create a class to extend std::string, (which I know is not recommended, but for the sake of the discussion just bear with it), and overload the +=, + operator. -Weffc++ gives me a warning because std::string has a non virtual destructor, but does it matter if the sub-class has no members and does not need to do anything in its destructor?
FYI the += overload was to do proper file path formatting, so the path class could be used like:
class path : public std::string {
//... overload, +=, +
//... add last_path_component, remove_path_component, ext, etc...
};
path foo = "/some/file/path";
foo = foo + "filename.txt";
std::string s = foo; //easy assignment to std::string
some_function_taking_std_string (foo); //easy implicit conversion
//and so on...
I just wanted to make sure someone doing this:
path* foo = new path();
std::string* bar = foo;
delete bar;
would not cause any problems with memory allocation?
So everyone has been saying you cant do it – it leads to undefined behaviour. However
there are some cases where it is safe. If you are never creating instances of your class dynamically then you should be OK. (i.e. no new calls)
That said, it is generally considered a bad thing to do as someone might try to create one polymorphically at some later date. ( You may be able to protect against this by having a private unimplemented operator new, but I’m not sure. )
I have two examples where I don’t hate deriving from classes with non-virtual destructors.
The first is creating syntactic sugar using temporaries … here’s a contrived example.
The other valid usage I can think of comes from the lack of template typedefs in C++. Here’s how you might use it.
Heres a more concrete example of this. You want to use std::map with a custom allocator for many different types, but you dont want the unmaintainable
littered through your code.