Skip to content

Commit

Permalink
Documentation: Tweak document about smart pointers a bit
Browse files Browse the repository at this point in the history
Add notes about assigning between FooPtr / NonnullFooPtr.
  • Loading branch information
awesomekling committed Mar 20, 2020
1 parent 03ec57b commit 2176a3d
Showing 1 changed file with 44 additions and 35 deletions.
79 changes: 44 additions & 35 deletions Documentation/SmartPointers.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,81 @@
# Serenity smart pointers
# SerenityOS smart pointers

----
## Introduction

There are three main C++ smart pointer types used in the Serenity operating system. Each type describes the ownership (or lack thereof) of the pointee.
There are three main C++ smart pointer types used in SerenityOS. Each type describes the ownership (or lack thereof) of the pointee.

The reason for using these pointers is to make it explicit through code who owns which resources, and how ownership is transferred. They also serve as a guard against memory leaks and use-after-free bugs.


----
## OwnPtr<T> and NonnullOwnPtr<T>

OwnPtr is used for single-owner objects. An object held by an OwnPtr is owned by that OwnPtr, and not by anybody else.
`OwnPtr` is used for single-owner objects. An object held in an `OwnPtr` is owned by that `OwnPtr`, and not by anybody else.

This means that the OwnPtr is responsible for deleting the pointee when the OwnPtr goes out of scope.
This means that the `OwnPtr` is responsible for deleting the pointee when the `OwnPtr` goes out of scope.

NonnullOwnPtr<T> is a special variant of OwnPtr with one additional property: it cannot be null. NonnullOwnPtr is suitable as a return type from functions that are guaranteed to never return null, and as an argument type where ownership is transferred, and the argument may not be null. In other words, if OwnPtr is "\*", then NonnullOwnPtr is "&".
`NonnullOwnPtr` is a special variant of `OwnPtr` with one additional property: it cannot be null. `NonnullOwnPtr` is suitable as a return type from functions that are guaranteed to never return null, and as an argument type where ownership is transferred, and the argument may not be null. In other words, if `OwnPtr` is "\*", then `NonnullOwnPtr` is "&".

There is a make<T>() helper that creates a new object and returns it wrapped in an NonnullOwnPtr.
There is a `make<T>()` helper that creates a new object and returns it wrapped in an `NonnullOwnPtr`.

{
NonnullOwnPtr<Foo> my_object = make<Foo>();
my_object->do_stuff();
// my_object goes out of scope here, and the Foo will be deleted.
}
```cpp
{
NonnullOwnPtr<Foo> my_object = make<Foo>();
my_object->do_stuff();
// my_object goes out of scope here, and the Foo will be deleted.
}
```

Note: A `NonnullOwnPtr` can be assigned to an `OwnPtr` but not vice versa. To transform an known-non-null `OwnPtr` into a `NonnullOwnPtr`, use `OwnPtr::release_nonnull()`.

----
## RefPtr<T> and NonnullRefPtr<T>

RefPtr is used for multiple-owner objects. An object held by a RefPtr is owned together by every pointer pointing to that object.
`RefPtr` is used for multiple-owner objects. An object held by a `RefPtr` is owned together by every pointer pointing to that object.

Shared ownership is implemented via reference counting.

NonnullRefPtr<T> is a special variant of RefPtr with one additional property: it cannot be null. NonnullRefPtr is suitable as a return type from functions that are guaranteed to never return null, and as an argument type where the argument may not be null. In other words, if RefPtr is "\*", then NonnullRefPtr is "&".
`NonnullRefPtr` is a special variant of `RefPtr` with one additional property: it cannot be null. `NonnullRefPtr` is suitable as a return type from functions that are guaranteed to never return null, and as an argument type where the argument may not be null. In other words, if `RefPtr` is "\*", then `NonnullRefPtr` is "&".

Objects can only be held by RefPtr if they meet certain criteria. Specifically, they need to implement the functions `ref()` and `unref()`.
Objects can only be held by `RefPtr` if they meet certain criteria. Specifically, they need to implement the functions `ref()` and `unref()`.

To make a class T reference counted, you can simply make it inherit from RefCounted<T>. This will add all the necessary pieces to T.
To make a class `T` reference-counted, you can simply make it inherit from `RefCounted<T>`. This will add all the necessary pieces to `T`.

**Note:** When constructing a RefCounted-derived class, the reference count starts out at 1 (since 0 would mean that the object has no owners and should be deleted.) The object must therefore be "adopted" by someone who takes responsibility of that 1. This is done through the global `adopt()` function:
**Note:** When constructing an object that derives from `RefCounted`, the reference count starts out at 1 (since 0 would mean that the object has no owners and should be deleted.) The object must therefore be "adopted" by someone who takes responsibility of that 1. This is done through the global `adopt()` function:

class Bar : public RefCounted<Bar> {
...
};
```cpp
class Bar : public RefCounted<Bar> {
...
};

RefPtr<Bar> our_object = adopt(*new Bar);
RefPtr<Bar> another_owner = our_object;
RefPtr<Bar> our_object = adopt(*new Bar);
RefPtr<Bar> another_owner = our_object;
```
In the above example, the Bar object will only be deleted once both "our\_object" and "another\_owner" are gone.
In the above example, the Bar object will only be deleted once both `our_object` and `another_owner` are gone.
Note: A `NonnullRefPtr` can be assigned to a `RefPtr` but not vice versa. To transform an known-non-null `RefPtr` into a `NonnullRefPtr`, either use `RefPtr::release_nonnull()` or simply dereference the `RefPtr` using its `operator*`.
----
## WeakPtr<T>
WeakPtr is used for object that somebody else owns. When the pointee of a WeakPtr is deleted, the WeakPtr will magically become null.
`WeakPtr` is used for objects that somebody else owns. When the pointee of a `WeakPtr` is deleted, the `WeakPtr` will magically become null.
Behind the scenes, this is implemented using the Weakable<T> template. If you want to make it possible for a class to be weakly-pointed-to, have it inherit from Weakable<T>.
Behind the scenes, this is implemented using the `Weakable` template. If you want to make it possible for a class `T` to be weakly-pointed-to, have it inherit from `Weakable<T>`.
To create a WeakPtr<T>, use `make_weak_ptr()`:
To create a `WeakPtr` to a weakable object, use `make_weak_ptr()`:
class Baz : public Weakable<Baz> {
....
};
```cpp
class Baz : public Weakable<Baz> {
....
};
WeakPtr<Baz> a_baz;
{
OwnPtr<Baz> my_baz = make<Baz>();
a_baz = my_baz->make_weak_ptr();
// a_baz now points to my_baz
}
// a_baz is now null, since my_baz went out of scope.
WeakPtr<Baz> a_baz;
{
OwnPtr<Baz> my_baz = make<Baz>();
a_baz = my_baz->make_weak_ptr();
// a_baz now points to my_baz
}
// a_baz is now null, since my_baz went out of scope.
```

0 comments on commit 2176a3d

Please sign in to comment.