Recently I am studying OOP using C++, and I am quite confused when I should use destruction function of my own in the following case:
class T1{
private:
int data;
public:
T1(){...};
~T1(){}; // should I write my own function here?
};
class T2{
private:
T1* pointer_to_T1;
public:
T2(){...};
~T2(){}; // should I write my own function here?
};
class Node{
public:
int data;
Node* next;
};
class T3{
private:
int size;
Node* head;
public:
T3(size){
head = new Node[size];
}
~T3(){}; // should I write my own function here?
};
There are three comments in my program above to clarify my question. I hope you could explain them and I would appreciate it if you could give me a general rule.
In case of class T3 you are allocating new memory, so you will have to delete the allocated memory segment in destructure.
class T3{
private:
int size;
Node* head;
public:
T3(size){
head = new Node[size];
}
~T3(){
delete[] head;
};
};
I'll attempt to answer in a general way not specific to your code snippets.
Two general scenarios commonly present themselves in which you'll need a non-trivial destructor. This is not a complete list; just the most common scenarios.
1) In a (polymorphic) hierarchy. If your class is a base class, intended to be derived from, there is a very good chance that your base class should have a non-trivial destructor. Moreover, that destructor should probably be virtual. This makes it possible to delete derived-class objects through the base-class pointer, like this:
class Foo
{
public:
virtual ~Foo(){}
};
class Bar : public Foo
{
};
int main()
{
Foo* obj = new Bar;
delete obj;
}
Without the virtual destructor, this program would exhibit Undefined Behavior.
2) When your class has members need more than trivial destruction. A simple example is if your class has a member that is a raw pointer (as in not a smart pointer) that was created using new. That pointer will need to be deleted, and the destructor is probably the right place to do it. A good indication that your class manages non-trivially-destructible members is if your class has either a copy constructor or a copy assignment operator (operator=). If your class has either then it probably needs both of them plus a destructor to handle whatever was assigned. (See Rule of Three) This isn't the only indication however -- you could have only a default constructor and still need a destructor. It depends on what your class does.
The destructor of a class should perform all actions needed when the object is deleted.
For example it need to free all the memory that was dynamically allocated by the class.
You should write a destructor when your class is a base class, and you expect polymorphic destruction, and when you want some logic to be ran when the object is destroyed.
If the object owns and manages resources, you probably need a constructor. Don't forget about the copy and assignment operators.
The object should cleanup after itself.
IE, if you ever allocate memory in your object, possibly being done in the constructor, then you should deallocate that memory in the destructor.
The destructor is meant to cleanup after your object. So it is also possible that you can do anything to help you do that.
Class T1 does not require to define explicitly the destructor. It will be enough to have the destructor implicitly defined by the compiler.
Class T2 needs to define the destructor explicitly that to deallocate its data member having type pointer. Otherwise there will be a memory leak.
Class Node does not need to define the destructor explicitly. It is class T3 that has to delete all pointers of class Node because it is it that controls the allocation and deallocation of nodes.
You need to declare a destructor:
if the class manages resources that need to be manually released when it's destroyed;
if it's intended to be a polymorphic base class, in which case it needs a virtual destructor to allow polymorphic deletion.
In the first case, you'll also need to provide, or delete, a copy constructor and copy-assignment operator; otherwise you could end up with two or more objects trying to manage the same resource. This is known as the "Rule of Three". Usually, you can use ready-made classes like containers and smart pointers to manage memory for you; so there's usually no need to muck around with destructors yourself. Some people refer to this as the "Rule of Zero".
In the second case, the destructor doesn't have to do anything (assuming the class isn't trying to manage any resources), it just needs to be virtual.
For your specific examples:
T1 doesn't need a destructor
T2 might, depending on whether it's supposed to manage whatever the pointer points to. If it does, then consider replacing the pointer with a smart pointer like std::unique_ptr<T1>.
T3 probably does, since it appears to be managing the dynamic array. You'll also need to consider the Rule of Three; or consider using std::vector<Node> to manage the array automatically.
Related
Let's assume I have three classes:
class A{
};
class B{
int S;
A* arr;
B(int s):S(s){
arr = new A[S];
}
~B(){
delete [] arr;
}
};
class C{
B& b;
C(B& b): b(b){}
};
Should I define explicitly a destructor in class C? What would it look like?
Should I define explicitly a destructor in class C?
To answer that question, you must know what your class does. Is the purpose of the class to manage allocated memory? Then, yes you probably need a destructor. Is the purpose to refer to an object managed by something else? Then why would you need a destructor? If you don't know what a destructor should do, then you quite often do not need one.
You should never use owning references, so there should be little reason for C to have a destructor, or it has to be changed drastically.
You also should not use owning bare pointers, so class B should also be changed. Easiest solution is to replace it with std::vector.
No, you don't need a destructor for C, but you do need a copy-constructor (as well as a move-constructor, copy-assignment operator and move-assignment operator) for class B if you want to correctly implement copy-semantics. As it is now if you were to make a copy of an object of class B, you would have to objects pointing to the same array - when the objects are destructed you would get a double delete causing undefined behavior.
You don't need to use a raw pointer. You can simply use a std::vector will handle the allocation of the elements as well as its destruction. That also means that you won't need to implement any other kinds of constructors or a destructor for B since std::vector handles copies and moves correctly.
Can anyone tell me what happens with object's memory if I forget to declare a destrucor in a C++ class? I mean, whether it is freed or causes memory leak?
An example or demo will be appreciated.
Thanks in advance.
It's often considered good practice to define a destructor for any non-trivial class (see the Rule of Three). However, in modern C++ (i.e. C++11 onwards), it's not as necessary as it used to be.
If your class is not inherited from anything else, any direct members (such as variables and objects) will be properly destroyed by the default destructor provided by the compiler. Similarly, if your object owns any heap-allocated objects which are wrapped in smart pointers, they will be destroyed safely too.
A problem arises if your object owns any heap-allocated data via raw pointers. The implicit destructor has no way of knowing what to do with them, so you will need a custom destructor to clear them up. For example:
class MyClass
{
int m_data1;
std::string m_data2;
std::shared_ptr<Widget> m_data3;
Widget *m_data4;
};
In the above example, members m_data1, m_data2, and m_data3 will all be cleared-up correctly without a custom destructor. However, the object pointed to by m_data4 will not be cleared up automatically. If it was allocated by MyClass, then it will usually result in a memory leak (unless it's getting freed by something else).
With all of that said, inheritance changes things in an important way. If your class is inherited by anything else then you should probably always give it a virtual destructor. If your object is deleted via a pointer to an inherited class, and that class does not have a virtual destructor, then the sub-class' destructor will never be called, potentially resulting in memory leaks.
For example:
class Parent
{
public:
Widget m_data1;
}
class Child : public Parent
{
public:
Widget m_data2;
}
int main()
{
Parent *ptr = new Child;
delete ptr; // <-- clears-up Parent but not Child
}
In the above example, ptr is of Parent type, so the delete only knows about the Parent part of the object. That means only m_data1 will be cleared-up correctly. Without a virtual destructor, it doesn't know about the Child part of the object, so m_data2 will not be cleared-up correctly (its destructor will never be called).
If destructor is not declared, compiler will generate destructor, that will call destructors of all members of object. Leak can be only if you are working with raw-memory (C files, memory allocation etc).
It depends on the class' data members. If the class manages resources, then it needs a destructor to release them (you should also provide a copy constructor and assignment operator, or make the class non-copyable and non-assignable).
If the class has built-in data members, or data members that manage their own resources, then the implicitly generated destructor is enough. It will call the destructor of all data members.
I've this C++ class:
class test{
char* p;
SomeClass* someObject;
test(){
...
p = (char*) malloc(1000);
someObject = new SomeClass();
...
}
~test(){}
}
Do I need to call free(p) or delete someObject explicitly in test destructor in order to free their allocated memory or that memory will free automatically?
You need to free all dynamically allocated memory in the destructor. This does not get done automatically.
Your class contains two pointers, and essentially has no control over what these point to. In fact, these could point to objects that you are not allowed to delete, for example:
struct Foo {};
struct Bar {
Foo* f_;
Foo(Foo* f) : f(f_) {}
};
int main() {
Foo f;
Bas b(&f); // b has a Foo ptr, but should it delete it?
}
So you can see that it doesn't really make sense for pointer data members to be deleted automatically.
As a general rule, if your class manages resources1, then you should take care of copy construction and assignment; that means, you should either disable them if that makes sense for the class, or provide implementation for them because the compiler generated ones would not work. For detail discussion on this topic, see the rule of three, and extensive discussions on stackoverflow:
What is The Rule of Three?
Rule-of-Three becomes Rule-of-Five with C++11?
If you don't follow this rule, then the default copy constructor and assignment operation will make a shallow copy and you will have more than one instance having pointers to the same dynamically allocated objects, which they will all try to delete upon destruction.
You can avoid manually deleting objects created with new by using smart pointers. In your case, where the class obviously owns the dynamically allocated object,you should look at C++11's std::unique_ptr or boost::scoped_ptr
Finally, you can really avoid all memory management problems by avoiding pointers all together, unless you really need to. You could replace your char* by an std::string for example:
class test{
std::string p;
SomeClass someObject;
//test() : someObject() {} // default construction is probably OK...
};
1. That is, it allocates and deallocates memory, or opens and closes network connection, or creates and destroy mutexes and so on.
Yes, you have to free anything you malloc and delete everything you new.
You can also avoid that by not storing pointers in your class.
class test{
public:
std::string p;
SomeClass someObject;
};
Yes, you need.
If you don't want, you can use the Smart Pointer
Yes, you need to free them explicitly. Pointer as a data type does not have any destructor. Compiler/execution enviroment does not have any means to guess if pointer points to anything meaningfull or not. Even if the value is meaningfull, it may point to some static object for example. Or it can point to some field of a bigger object. Compiler is not doing any automatic cleanup on pointers.
The memory is technically leaked if you do not reclaim it when the instance of test is destructed. You could use a smart pointer instead to avoid calling free or delete explicitly in the destructor.
struct Free { void operator () (void *p) const { free(p); } };
class test {
std::unique_ptr<char, Free> p;
std::unique_ptr<SomeClass> someObject;
test () : p(static_cast<char *>(malloc(1000)),
someObject(new SomeClass)
{ //...
}
~test () {}
};
This uses the destructor of the smart pointer to perform the clean up action for you.
If test were only used as const global instances, then it is less important to implement the cleanup since the memory would not be reclaimed until the execution had ended anyway. But it is good practice to always implement the cleanup, because it would make the code correct now, and test may be used differently in the future.
My question is simple, but I haven't been able to find the question anywhere.
If I have a class like such
class A {
vector<int> data;
}
When an instance of A gets destroyed will data also get destroyed properly, or should I write a destructor for A that calls data's destructor? Basically I worried about whether the dynamic memory of vector will not be freed when an instance of A is destroyed. I suspect the answer is that data is freed properly, but I don't want to find out I'm wrong the hard way.
Further, if A was a struct would the destructor for data get called when a local instance of A falls out of scope?
Yes, data will be destroyed automatically, you need not do anything to achieve it. vector will handle the cleaning up of the dynamic memory allocated by it. The vector's destructor will be called automatically when an instance of A is destroyed.
There is no difference in behavior irrespective of whether A is a class or struct.
No need, data member's destructors are always called.
An explicit destructor is useful manual memory management
struct a{
int* ip;
a()
: ip(new int(5))
{ }
~a() { delete ip; }
};
That said, you should generally speaking use RAII containers (such as smart pointers) so I personally rarely write dtors there days.
And exception to that is to declare a base classes dtor as virtual.
struct base {
virtual ~base() {}
};
struct child : public base {
//base and child destructor automatically called
}
A default-destructor is created automatically by the compiler if you do not define one yourself. In general, you do not need to create your own destructor unless you have pointer data-members that "own" the memory they point to, and/or you are designing your class to be derived by other classes, at which point you would want to at least declare an empty virtual destructor.
In all cases, both with your own destructor, as well as the default compiler-created destructor, all destructors for non-static data-members as well as any base-classes of the current class are called at the end of the destructor and before the destructor function itself returns.
If I create a class MyClass and it has some private member say MyOtherClass, is it better to make MyOtherClass a pointer or not? What does it mean also to have it as not a pointer in terms of where it is stored in memory? Will the object be created when the class is created?
I noticed that the examples in QT usually declare class members as pointers when they are classes.
If I create a class MyClass and it has some private member say MyOtherClass, is it better to make MyOtherClass a pointer or not?
you should generally declare it as a value in your class. it will be local, there will be less chance for errors, fewer allocations -- ultimately fewer things that could go wrong, and the compiler can always know it is there at a specified offset so... it helps optimization and binary reduction at a few levels. there will be a few cases where you know you'll have to deal with pointer (i.e. polymorphic, shared, requires reallocation), it is typically best to use a pointer only when necessary - especially when it is private/encapsulated.
What does it mean also to have it as not a pointer in terms of where it is stored in memory?
its address will be close to (or equal to) this -- gcc (for example) has some advanced options to dump class data (sizes, vtables, offsets)
Will the object be created when the class is created?
yes - the size of MyClass will grow by sizeof(MyOtherClass), or more if the compiler realigns it (e.g. to its natural alignment)
Where is your member stored in memory?
Take a look at this example:
struct Foo { int m; };
struct A {
Foo foo;
};
struct B {
Foo *foo;
B() : foo(new Foo()) { } // ctor: allocate Foo on heap
~B() { delete foo; } // dtor: Don't forget this!
};
void bar() {
A a_stack; // a_stack is on stack
// a_stack.foo is on stack too
A* a_heap = new A(); // a_heap is on stack (it's a pointer)
// *a_heap (the pointee) is on heap
// a_heap->foo is on heap
B b_stack; // b_stack is on stack
// b_stack.foo is on stack
// *b_stack.foo is on heap
B* b_heap = new B(); // b_heap is on stack
// *b_heap is on heap
// b_heap->foo is on heap
// *(b_heap->foo is on heap
delete a_heap;
delete b_heap;
// B::~B() will delete b_heap->foo!
}
We define two classes A and B. A stores a public member foo of type Foo. B has a member foo of type pointer to Foo.
What's the situation for A:
If you create a variable a_stack of type A on the stack, then the object (obviously) and its members are on the stack too.
If you create a pointer to A like a_heap in the above example, just the pointer variable is on the stack; everything else (the object and it's members) are on the heap.
What does the situation look like in case of B:
you create B on the stack: then both the object and its member foo are on the stack, but the object that foo points to (the pointee) is on the heap. In short: b_stack.foo (the pointer) is on the stack, but *b_stack.foo the (pointee) is on the heap.
you create a pointer to B named b_heap: b_heap (the pointer) is on the stack, *b_heap (the pointee) is on the heap, as well as the member b_heap->foo and *b_heap->foo.
Will the object be automagically created?
In case of A: Yes, foo will automatically be created by calling the implicit default constructor of Foo. This will create an integer but will not intitialize it (it will have a random number)!
In case of B: If you omit our ctor and dtor then foo (the pointer) will also be created and initialized with a random number which means that it will point to a random location on the heap. But note, that the pointer exists! Note also, that the implicit default constructor won't allocate something for foo for you, you have to do this explicitly. That's why you usually need an explicit constructor and a accompanying destructor to allocate and delete the pointee of your member pointer. Don't forget about copy semantics: what happens to the pointee if your copy the object (via copy construction or assignment)?
What's the point of all of this?
There are several use cases of using a pointer to a member:
To point to an object you don't own. Let's say your class needs access to a huge data structure that is very costly to copy. Then you could just save a pointer to this data structure. Be aware that in this case creation and deletion of the data structure is out of the scope of your class. Someone other has to take care.
Increasing compilation time, since in your header file the pointee does not have to be defined.
A bit more advanced; When your class has a pointer to another class that stores all private members, the "Pimpl idiom": http://c2.com/cgi/wiki?PimplIdiom, take also a look at Sutter, H. (2000): Exceptional C++, p. 99--119
And some others, look at the other answers
Advice
Take extra care if your members are pointers and you own them. You have to write proper constructors, destructors and think about copy constructors and assignment operators. What happens to the pointee if you copy the object? Usually you will have to copy construct the pointee as well!
In C++, pointers are objects in their own right. They're not really tied to whatever they point to, and there's no special interaction between a pointer and its pointee (is that a word?)
If you create a pointer, you create a pointer and nothing else. You don't create the object that it might or might not point to. And when a pointer goes out of scope, the pointed-to object is unaffected. A pointer doesn't in any way affect the lifetime of whatever it points to.
So in general, you should not use pointers by default. If your class contains another object, that other object shouldn't be a pointer.
However, if your class knows about another object, then a pointer might be a good way to represent it (since multiple instances of your class can then point to the same instance, without taking ownership of it, and without controlling its lifetime)
The common wisdom in C++ is to avoid the use of (bare) pointers as much as possible. Especially bare pointers that point to dynamically allocated memory.
The reason is because pointers make it more difficult to write robust classes, especially when you also have to consider the possibility of exceptions being thrown.
I follow the following rule: if the member object lives and dies with the encapsulating object, do not use pointers. You will need a pointer if the member object has to outlive the encapsulating object for some reason. Depends on the task at hand.
Usually you use a pointer if the member object is given to you and not created by you. Then you usually don't have to destroy it either.
This question could be deliberated endlessly, but the basics are:
If MyOtherClass is not a pointer:
The creation and destruction of MyOtherClass is automatic, which can reduce bugs.
The memory used by MyOtherClass is local to the MyClassInstance, which could improve performance.
If MyOtherClass is a pointer:
The creation and destruction of MyOtherClass is your responsibility
MyOtherClass may be NULL, which could have meaning in your context and could save memory
Two instances of MyClass could share the same MyOtherClass
Some advantages of pointer member:
The child (MyOtherClass) object can have different lifetime than its parent (MyClass).
The object can possibly be shared between several MyClass (or other) objects.
When compiling the header file for MyClass, the compiler doesn't necessarily have to know the definition of MyOtherClass. You don't have to include its header, thus decreasing compile times.
Makes MyClass size smaller. This can be important for performance if your code does a lot of copying of MyClass objects. You can just copy the MyOtherClass pointer and implement some kind of reference counting system.
Advantages of having the member as an object:
You don't have to explicitely write code to create and destroy the object. It's easier and and less error-prone.
Makes memory management more efficient because only one block of memory needs to be allocated instead of two.
Implementing assignment operators, copy/move constructors etc is much simpler.
More intuitive
If you make the MyOtherClass object as member of your MyClass:
size of MyClass = size of MyClass + size of MyOtherClass
If you make the MyOtherClass object as pointer member of your MyClass:
size of MyClass = size of MyClass + size of any pointer on your system
You might want to keep MyOtherClass as a pointer member because it gives you the flexibility to point it to any other class that is derived from it. Basically helps you implement dynamice polymorphism.
It depends... :-)
If you use pointers to say a class A, you have to create the object of type A e.g. in the constructor of your class
m_pA = new A();
Moreover, don't forget to destroy the object in the destructor or you have a memory leak:
delete m_pA;
m_pA = NULL;
Instead, having an object of type A aggregated in your class is easier, you can't forget to destroy it, because this is done automatically at the end of lifetime of your object.
On the other hand, having a pointer has the following advantages:
If your object is allocated on the
stack and type A uses a lot of memory
this won't be allocated from the
stack but from the heap.
You can construct your A object later (e.g. in a method Create) or destroy it earlier (in method Close)
An advantage of the parent class maintaining the relation to a member object as a (std::auto_ptr) pointer to the member object is that you can forward declare the object rather than having to include the object's header file.
This decouples the classes at build time allowing to modify the member object's header class without causing all the clients of your parent class to be recompiled as well even though they probably do not access the member object's functions.
When you use an auto_ptr, you only need to take care of construction, which you could typically do in the initializer list. Destruction along with the parent object is guaranteed by the auto_ptr.
The simple thing to do is to declare your members as objects. This way, you do not have to care about copy construction, destruction and assignment. This is all taken care of automatically.
However, there are still some cases when you want pointers. After all, managed languages (like C# or Java) actually hold member objects by pointers.
The most obvious case is when the object to be kept is polymorphic. In Qt, as you pointed out, most objects belong to a huge hierarchy of polymorphic classes, and holding them by pointers is mandatory since you don't know at advance what size will the member object have.
Please beware of some common pitfalls in this case, especially when you deal with generic classes. Exception safety is a big concern:
struct Foo
{
Foo()
{
bar_ = new Bar();
baz_ = new Baz(); // If this line throw, bar_ is never reclaimed
// See copy constructor for a workaround
}
Foo(Foo const& x)
{
bar_ = x.bar_.clone();
try { baz_ = x.baz_.clone(); }
catch (...) { delete bar_; throw; }
}
// Copy and swap idiom is perfect for this.
// It yields exception safe operator= if the copy constructor
// is exception safe.
void swap(Foo& x) throw()
{ std::swap(bar_, x.bar_); std::swap(baz_, x.baz_); }
Foo& operator=(Foo x) { x.swap(*this); return *this; }
private:
Bar* bar_;
Baz* baz_;
};
As you see, it is quite cumbersome to have exception safe constructors in the presence of pointers. You should look at RAII and smart pointers (there are plenty of resources here and somewhere else on the web).