Skip to content

Small nits for destructors cpp #4826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 30, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 16 additions & 33 deletions docs/cpp/destructors-cpp.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
description: "Learn more about: Destructors (C++)"
title: "Destructors (C++)"
ms.date: "07/20/2019"
ms.date: "11/29/2023"
helpviewer_keywords: ["objects [C++], destroying", "destructors, C++"]
---
# Destructors (C++)

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()`.
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`** or **`delete[]`**. A destructor has the same name as the class and is preceded by a tilde (`~`). For example, the destructor for class `String` is declared: `~String()`.

If you don't define a destructor, the compiler provides 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.
If you don't define a destructor, the compiler provides a default one, and for some classes this is sufficient. You need to define a custom destructor when the class maintains resources that must be explicitly released, such as handles to system resources or pointers to memory that should be released when an instance of the class is destroyed.

Consider the following declaration of a `String` class:

Expand Down Expand Up @@ -49,7 +49,7 @@ int main() {
}
```

In the preceding example, the destructor `String::~String` uses the **`delete`** operator to deallocate the space dynamically allocated for text storage.
In the preceding example, the destructor `String::~String` uses the **`delete[]`** operator to deallocate the space dynamically allocated for text storage.

## Declaring destructors

Expand All @@ -58,25 +58,19 @@ Destructors are functions with the same name as the class but preceded by a tild
Several rules govern the declaration of destructors. Destructors:

- Don't accept arguments.

- Don't return a value (or **`void`**).

- Can't be declared as **`const`**, **`volatile`**, or **`static`**. However, they can be invoked for the destruction of objects declared as **`const`**, **`volatile`**, or **`static`**.

- Can be declared as **`virtual`**. Using virtual destructors, you can destroy objects without knowing their type—the correct destructor for the object is invoked using the virtual function mechanism. Destructors can also be declared as pure virtual functions for abstract classes.

## Using destructors

Destructors are called when one of the following events occurs:

- A local (automatic) object with block scope goes out of scope.

- An object allocated using the **`new`** operator is explicitly deallocated using **`delete`**.

- Use **`delete`** to deallocate an object allocated using **`new`**. Using **`delete[]`** results in undefined behaviour.
- Use **`delete[]`** to deallocate an object allocated using **`new[]`**. Using **`delete`** results in undefined behaviour.
- The lifetime of a temporary object ends.

- A program ends and global or static objects exist.

- The destructor is explicitly called using the destructor function's fully qualified name.

Destructors can freely call class member functions and access class member data.
Expand Down Expand Up @@ -123,8 +117,10 @@ int main() {
B3 * b2 = new B3;
delete b2;
}
```

Output: A3 dtor
```output
A3 dtor
A2 dtor
A1 dtor

Expand All @@ -143,48 +139,35 @@ Destructors for virtual base classes are called in the reverse order of their ap
Five classes, labeled A through E, are arranged in an inheritance graph. Class E is the base class of B, C, and D. Classes C and D are the base class of A and B.
:::image-end:::

The following lists the class heads for the classes shown in the figure.
The following lists the class definitions for the classes shown in the figure:

```cpp
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 B
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 B {};
```

To 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:

1. Traverse the graph left, starting at the deepest point in the graph (in this case, `E`).

1. Perform leftward traversals until all nodes have been visited. Note the name of the current node.

1. Revisit the previous node (down and to the right) to find out whether the node being remembered is a virtual base class.

1. If the remembered node is a virtual base class, scan the list to see whether it has already been entered. If it isn't a virtual base class, ignore it.

1. If the remembered node isn't yet in the list, add it to the bottom of the list.

1. Traverse the graph up and along the next path to the right.

1. Go to step 2.

1. When the last upward path is exhausted, note the name of the current node.

1. Go to step 3.

1. Continue this process until the bottom node is again the current node.

Therefore, for class `E`, the order of destruction is:

1. The non-virtual base class `E`.

1. The non-virtual base class `D`.

1. The non-virtual base class `C`.

1. The virtual base class `B`.

1. The virtual base class `A`.

This process produces an ordered list of unique entries. No class name appears twice. Once the list is constructed, it's walked in reverse order, and the destructor for each of the classes in the list from the last to the first is called.
Expand Down Expand Up @@ -239,5 +222,5 @@ Explicitly defining a destructor, copy constructor, or copy assignment operator

## See also

[Copy Constructors and Copy Assignment Operators](../cpp/copy-constructors-and-copy-assignment-operators-cpp.md)</br>
[Copy Constructors and Copy Assignment Operators](../cpp/copy-constructors-and-copy-assignment-operators-cpp.md)\
[Move Constructors and Move Assignment Operators](../cpp/move-constructors-and-move-assignment-operators-cpp.md)