In C#, destructor (finalizer) is used to destroy objects of class when the scope of an object ends. It has the same name as the class and starts with a tilde ~. For example, Show Here, ~Test() is the destructor. Example 1: Working of C# Destructorusing System; namespace CsharpDestructor { class Person { public Person() { Console.WriteLine("Constructor called."); } // destructor~Person() { Console.WriteLine("Destructor called."); } public static void Main(string [] args) { //creates object of Person Person p1 = new Person(); } } }Output Constructor called. Destructor called.In the above example, we have created a destructor ~Person inside the Person class. When we create an object of the Person class, the constructor is called. After the scope of the object ends, object p1 is no longer needed. So, the destructor is called implicitly which destroys object p1. Example 2: C# Destructorusing System; namespace CsharpDestructor { class Person { string name; void getName() { Console.WriteLine("Name: " + name); }// destructor ~Person() { Console.WriteLine("Destructor called."); } public static void Main(string [] args) { // creates object of Person Person p1 = new Person(); p1.name = "Ed Sheeran"; p1.getName(); } } }Output Name: Ed Sheeran Destructor called.Features of DestructorsThere are some important features of the C# destructor. They are as follows:
Answer includes properties / characteristics of destructor in C++ language for a class. Answer: Before listing characteristics of destructor, let’s see the declaration of destructor in a class. Below ~MyClass() is the destructor of a class. class MyClass{ public: MyClass(){}//Constructor ~MyClass(){}//Destructor };Properties of destructor in C++:
Tell me properties of destructor in C++ as many as you can.
A destructor is a member function that is invoked automatically when the object goes out of scope or is explicitly destroyed by a call to delete. A destructor has the same name as the class, preceded by a tilde (~). For example, the destructor for class String is declared: ~String(). If you do not define a destructor, the compiler will provide a default one; for many classes this is sufficient. You only need to define a custom destructor when the class stores handles to system resources that need to be released, or pointers that own the memory they point to. Consider the following declaration of a String class: // spec1_destructors.cpp #include <string> class String { public: String( char *ch ); // Declare constructor ~String(); // and destructor. private: char *_text; size_t sizeOfText; }; // Define the constructor. String::String( char *ch ) { sizeOfText = strlen( ch ) + 1; // Dynamically allocate the correct amount of memory. _text = new char[ sizeOfText ]; // If the allocation succeeds, copy the initialization string. if( _text ) strcpy_s( _text, sizeOfText, ch ); } // Define the destructor. String::~String() { // Deallocate the memory that was previously reserved // for this string. delete[] _text; } int main() { String str("The piper in the glen..."); }In the preceding example, the destructor String::~String uses the delete operator to deallocate the space dynamically allocated for text storage. Declaring destructorsDestructors are functions with the same name as the class but preceded by a tilde (~) Several rules govern the declaration of destructors. Destructors:
Using destructorsDestructors are called when one of the following events occurs:
Destructors can freely call class member functions and access class member data. There are two restrictions on the use of destructors:
Order of destructionWhen an object goes out of scope or is deleted, the sequence of events in its complete destruction is as follows:
Virtual base classesDestructors for virtual base classes are called in the reverse order of their appearance in a directed acyclic graph (depth-first, left-to-right, postorder traversal). the following figure depicts an inheritance graph. Inheritance graph that shows virtual base classes The following lists the class heads for the classes shown in the figure. class A class B class C : virtual public A, virtual public B class D : virtual public A, virtual public B class E : public C, public D, virtual public BTo determine the order of destruction of the virtual base classes of an object of type E, the compiler builds a list by applying the following algorithm:
Therefore, for class E, the order of destruction is:
This process produces an ordered list of unique entries. No class name appears twice. Once the list is constructed, it is walked in reverse order, and the destructor for each of the classes in the list from the last to the first is called. The order of construction or destruction is primarily important when constructors or destructors in one class rely on the other component being created first or persisting longer — for example, if the destructor for A (in the figure shown above) relied on B still being present when its code executed, or vice versa. Such interdependencies between classes in an inheritance graph are inherently dangerous because classes derived later can alter which is the leftmost path, thereby changing the order of construction and destruction. Non-virtual base classesThe destructors for non-virtual base classes are called in the reverse order in which the base class names are declared. Consider the following class declaration: class MultInherit : public Base1, public Base2 ...In the preceding example, the destructor for Base2 is called before the destructor for Base1. Explicit destructor callsCalling a destructor explicitly is seldom necessary. However, it can be useful to perform cleanup of objects placed at absolute addresses. These objects are commonly allocated using a user-defined new operator that takes a placement argument. The delete operator cannot deallocate this memory because it is not allocated from the free store (for more information, see The new and delete Operators). A call to the destructor, however, can perform appropriate cleanup. To explicitly call the destructor for an object, s, of class String, use one of the following statements: s.String::~String(); // non-virtual call ps->String::~String(); // non-virtual call s.~String(); // Virtual call ps->~String(); // Virtual callThe notation for explicit calls to destructors, shown in the preceding, can be used regardless of whether the type defines a destructor. This allows you to make such explicit calls without knowing if a destructor is defined for the type. An explicit call to a destructor where none is defined has no effect. Robust programmingA class needs a destructor if it acquires a resource, and to manage the resource safely it probably has to implement a copy constructor and a copy assignment. If these special functions are not defined by the user, they are implicitly defined by the compiler. The implicitly generated constructors and assignment operators perform shallow, memberwise copy, which is almost certainly wrong if an object is managing a resource. In the next example, the implicitly generated copy constructor will make the pointers str1.text and str2.text refer to the same memory, and when we return from copy_strings(), that memory will be deleted twice, which is undefined behavior: void copy_strings() { String str1("I have a sense of impending disaster..."); String str2 = str1; // str1.text and str2.text now refer to the same object } // delete[] _text; deallocates the same memory twice // undefined behaviorExplicitly defining a destructor, copy constructor, or copy assignment operator prevents implicit definition of the move constructor and the move assignment operator. In this case, failing to provide move operations is usually, if copying is expensive, a missed optimization opportunity. See alsoCopy Constructors and Copy Assignment Operators |