Skip to content
API Documentation
BastionGuard™
LifetimeGuard.hpp
Go to the documentation of this file.
1/*
2 * BastionGuard™
3 * Copyright (C) 2025–2026 Calogero Scarnà
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * BastionGuard™ is a trademark of Calogero Scarnà.
10 */
11
12#pragma once
13
14#include <atomic>
15#include <memory>
16#include <utility>
17
18// Utility condivisa per proteggere i lambda che catturano `this` e vengono
19// eseguiti asincronicamente (std::thread::detach, Glib::signal_idle,
20// callback di Gio::AsyncResult, ecc.) dal rischio di accedere a un oggetto
21// già distrutto.
22//
23// PATTERN DI USO:
24//
25// class MyPage : public Gtk::Box {
26// public:
27// MyPage() {
28// alive_ = std::make_shared<std::atomic<bool>>(true);
29// }
30//
31// ~MyPage() override {
32// // Segnala ai lambda in volo che l'oggetto è morto.
33// // I lambda faranno early-return invece di toccare `this`.
34// if (alive_) alive_->store(false);
35// }
36//
37// void do_async_work() {
38// auto alive = alive_; // cattura per valore (copy dello shared_ptr)
39// std::thread([this, alive]() {
40// // ... lavoro in background ...
41// if (!alive || !alive->load()) return; // oggetto morto
42// Glib::signal_idle().connect_once([this, alive]() {
43// if (!alive || !alive->load()) return;
44// // safe: possiamo usare `this`
45// update_ui();
46// });
47// }).detach();
48// }
49//
50// private:
51// std::shared_ptr<std::atomic<bool>> alive_;
52// };
53//
54// NOTE:
55// - Il flag è `std::shared_ptr<std::atomic<bool>>`: garantisce sia
56// atomicità sulla lettura/scrittura del bool, sia che la memoria che
57// contiene il flag resti valida finché almeno un lambda lo referenzia.
58// - Il costo è trascurabile (una refcount atomic inc/dec per lambda).
59// - Non protegge da tutti i use-after-free possibili: se il lambda
60// dereferenzia `this` PRIMA del check, crasha lo stesso. Il check va
61// fatto come prima istruzione utile del lambda.
62
63namespace BastionGuard {
64
65using AliveFlag = std::shared_ptr<std::atomic<bool>>;
66
68 return std::make_shared<std::atomic<bool>>(true);
69}
70
71// Esegue `fn()` solo se `alive` è ancora valido e settato a true.
72// Utile come wrapper leggibile nei lambda.
73template <typename Fn>
74inline void if_alive(const AliveFlag& alive, Fn&& fn) {
75 if (alive && alive->load(std::memory_order_acquire)) {
76 std::forward<Fn>(fn)();
77 }
78}
79
80} // namespace BastionGuard
void if_alive(const AliveFlag &alive, Fn &&fn)
std::shared_ptr< std::atomic< bool > > AliveFlag
AliveFlag make_alive_flag()