Tasking::Storage Class | Extending Qt Creator Manual
Description: A class template for custom data exchange in the running task tree.

- Extending Qt Creator Manual
- TaskingSolution
- Storage
- Extending Qt Creator Manual 18.0.2

# Tasking::Storage Class

template <typename StorageStruct> class Tasking::Storage

A class template for custom data exchange in the running task tree. More...

Header: | `#include <solutions/tasking/tasktree.h>`
Inherits: | Tasking::StorageBase

- List of all members, including inherited members

Note: All functions in this class are reentrant.

## Public Functions

| Storage()
StorageStruct * | activeStorage() const
StorageStruct & | operator*() const
StorageStruct * | operator->() const

## Detailed Description

The Storage class template is responsible for dynamically creating and destructing objects of the custom `StorageStruct` type. The creation and destruction are managed by the running task tree. If a Storage object is placed inside a Group element, the running task tree creates the `StorageStruct` object when the group is started and before the group's setup handler is called. Later, whenever any handler inside this group is called, the task tree activates the previously created instance of the `StorageStruct` object. This includes all tasks' and groups' setup and done handlers inside the group where the Storage object was placed, also within the nested groups. When a copy of the Storage object is passed to the handler via the lambda capture, the handler may access the instance activated by the running task tree via the operator->(), operator*(), or activeStorage() method. If two handlers capture the same Storage object, one of them may store a custom data there, and the other may read it afterwards. When the group is finished, the previously created instance of the `StorageStruct` object is destroyed after the group's done handler is called.

An example of data exchange between tasks:

     const Storage<QString> storage;

     const auto onFirstDone = [storage](const Task &task) {
         // Assings QString, taken from the first task result, to the active QString instance
         // of the Storage object.
         *storage = task.getResultAsString();
     };

     const auto onSecondSetup = [storage](Task &task) {
         // Reads QString from the active QString instance of the Storage object and use it to
         // configure the second task before start.
         task.configureWithString(*storage);
     };

     const Group root {
         // The running task tree creates QString instance when root in entered
         storage,
         // The done handler of the first task stores the QString in the storage
         TaskItem(..., onFirstDone),
         // The setup handler of the second task reads the QString from the storage
         TaskItem(onSecondSetup, ...)
     };

Since the root group executes its tasks sequentially, the `onFirstDone` handler is always called before the `onSecondSetup` handler. This means that the QString data, read from the `storage` inside the `onSecondSetup` handler's body, has already been set by the `onFirstDone` handler. You can always rely on it in sequential execution mode.

The Storage internals are shared between all of its copies. That is why the copies of the Storage object inside the handlers' lambda captures still refer to the same Storage instance. You may place multiple Storage objects inside one Group element, provided that they do not include copies of the same Storage object. Otherwise, an assert is triggered at runtime that includes an error message. However, you can place copies of the same Storage object in different Group elements of the same recipe. In this case, the running task tree will create multiple instances of the `StorageStruct` objects (one for each copy) and storage shadowing will take place. Storage shadowing works in a similar way to C++ variable shadowing inside the nested blocks of code:

     Storage<QString> storage;

     const Group root {
         storage,                             // Top copy, 1st instance of StorageStruct
         onGroupSetup([storage] { ... }),     // Top copy is active
         Group {
             storage,                         // Nested copy, 2nd instance of StorageStruct,
                                              // shadows Top copy
             onGroupSetup([storage] { ... }), // Nested copy is active
         },
         Group {
             onGroupSetup([storage] { ... }), // Top copy is active
         }
     };

The Storage objects may also be used for passing the initial data to the executed task tree, and for reading the final data out of the task tree before it finishes. To do this, use onStorageSetup() or onStorageDone(), respectively.

Note: If you use an unreachable Storage object inside the handler, because you forgot to place the storage in the recipe, or placed it, but not in any handler's ancestor group, you may expect a crash, preceded by the following message: The referenced storage is not reachable in the running tree. A nullptr will be returned which might lead to a crash in the calling code. It is possible that no storage was added to the tree, or the storage is not reachable from where it is referenced.

## Member Function Documentation

### Storage::Storage()

Creates a storage for the given `StorageStruct` type.

Note: All copies of `this` object are considered to be the same Storage instance.

### StorageStruct *Storage::activeStorage() const

Returns a pointer to the active `StorageStruct` object, created by the running task tree. Use this function only from inside the handler body of any GroupItem element placed in the recipe, otherwise you may expect a crash. Make sure that Storage is placed in any group ancestor of the handler's group item.

Note: The returned pointer is valid as long as the group that created this instance is still running.

See also operator->() and operator*().

### `[noexcept]` StorageStruct &Storage::operator*() const

Returns a reference to the active `StorageStruct` object, created by the running task tree. Use this function only from inside the handler body of any GroupItem element placed in the recipe, otherwise you may expect a crash. Make sure that Storage is placed in any group ancestor of the handler's group item.

Note: The returned reference is valid as long as the group that created this instance is still running.

See also activeStorage() and operator->().

### `[noexcept]` StorageStruct *Storage::operator->() const

Returns a pointer to the active `StorageStruct` object, created by the running task tree. Use this function only from inside the handler body of any GroupItem element placed in the recipe, otherwise you may expect a crash. Make sure that Storage is placed in any group ancestor of the handler's group item.

Note: The returned pointer is valid as long as the group that created this instance is still running.

See also activeStorage() and operator*().