WebFront C++23
FR ↗GitHub ↗

Volume II / CHAPTER 02

For understanding and contributing

An application and its connections

A window can disappear while a call is waiting for its reply. Let us see which objects must remain alive.

Notation conventions

Function names, types, commands, options and filenames appear in monospace, for example describe, wf test or main.cpp. Italics introduce a term at its definition. Code blocks give the fragments to enter; the preceding text states their location and prerequisites.

What we construct

In a small example, we usually begin with a webfront::WebFront object. That name saves us from choosing all its parts. Reading further through the headers brings us to the more general BasicWF<NetProvider, Filesystem, Policy, Frontend> type.

Its parameters represent fairly concrete choices: obtain network bytes, find requested resources, choose a buffer policy and open the page. An ordinary application can keep the defaults. A test can replace some parts with objects whose behaviour it controls.

Implementation lives in headers and is integrated through the WebFront::WebFront CMake target. That is what header-only means here. Dependencies and template instantiation work still exist, and definitions must remain valid when included in several translation units.

What keeps a connection alive?

Suppose a browser is connected and an operation is waiting for its next message. The connection cannot disappear merely because the program requested window closure: the waiting operation still uses it.

BasicWF retains the server, WebLink connections, registered callbacks and server thread. A WebLink handles bridge exchanges with one browser. These objects give us specific places to look for owners.

The difficulty comes at the end: operations must finish their last accesses before the objects are released. We shall return to that ordering in the shutdown chapter.

Recognising the right browser

A UI value identifies the browser we want to address. Copying the value is useful, but does not keep the application alive. Its uses must still finish before application destruction.

There is another, less obvious trap. Imagine that a connection has number 7, closes, and that number is later assigned to a new connection. An old UI value must not reach the new browser.

BasicUI therefore retains a generation as well as the application and connection number. The number may be reused; the generation distinguishes the connections. A typed call to the old one fails instead of accidentally receiving another browser’s reply.

A callback can outlive its creator

Registering a callback gives the application a function to call later. The word “later” deserves attention. If the function captures a local variable by reference, that variable may have disappeared when the browser causes the call.

The same problem arises when a retained handler captures a forwarding-reference parameter by reference. Argument passing was valid during registration; that alone cannot make the capture valid for future calls.

Subscriptions raise a related question. onUIStarted sets the application handler. A component that also wants notification uses subscribeUIStarted and retains the returned UISubscription. Its code then shows how long it wishes to participate, without replacing the handler already installed.

Check your understanding

Does copying a UI extend the application’s lifetime?