> For the complete documentation index, see [llms.txt](https://swift.unicorndonkeys.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://swift.unicorndonkeys.com/guida-al-linguaggio/sicurezza-della-memoria.md).

# Sicurezza della memoria (Memory Safety)

Struttura il tuo codice per evitare conflitti durante l'accesso alla memoria.

Per impostazione predefinita, Swift impedisce che nel tuo codice si verifichino comportamenti non sicuri. Per esempio, Swift garantisce che le variabili siano inizializzate prima di essere usate, che non si acceda alla memoria dopo che è stata deallocata, e che gli indici degli array vengano controllati per individuare errori di accesso fuori dai limiti.

Swift si assicura inoltre che più accessi alla stessa area di memoria non entrino in conflitto, richiedendo che il codice che modifica una posizione in memoria abbia accesso esclusivo a quella memoria. Poiché Swift gestisce la memoria automaticamente, la maggior parte delle volte non hai affatto bisogno di pensare all'accesso alla memoria. Tuttavia, è importante capire dove possono verificarsi potenziali conflitti, in modo da evitare di scrivere codice che abbia accessi in conflitto alla memoria. Se il tuo codice contiene effettivamente dei conflitti, otterrai un errore in fase di compilazione o in fase di esecuzione.

## Comprendere gli accessi in conflitto alla memoria <a href="#comprendere-gli-accessi-in-conflitto-alla-memoria" id="comprendere-gli-accessi-in-conflitto-alla-memoria"></a>

Nel tuo codice avviene un accesso alla memoria quando fai cose come impostare il valore di una variabile o passare un argomento a una funzione. Per esempio, il codice seguente contiene sia un accesso in lettura sia un accesso in scrittura:

```swift
// Un accesso in scrittura alla memoria in cui è memorizzato one.
var one = 1

// Un accesso in lettura dalla memoria in cui è memorizzato one.
print("We're number \(one)!")
```

Un accesso in conflitto alla memoria può verificarsi quando parti diverse del tuo codice cercano di accedere alla stessa posizione in memoria nello stesso momento. Più accessi a una posizione in memoria nello stesso momento possono produrre un comportamento imprevedibile o incoerente. In Swift, esistono modi di modificare un valore che si estendono su diverse righe di codice, rendendo possibile tentare di accedere a un valore nel bel mezzo della sua stessa modifica.

Puoi vedere un problema simile pensando a come aggiorni un budget scritto su un pezzo di carta. Aggiornare il budget è un processo in due fasi: prima aggiungi i nomi e i prezzi degli articoli, e poi modifichi l'importo totale per riflettere gli articoli attualmente presenti nell'elenco. Prima e dopo l'aggiornamento, puoi leggere qualsiasi informazione dal budget e ottenere una risposta corretta, come mostrato nella figura seguente.

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FSVElmjeW4PMNZ7l9qwcK%2Fmemory_shopping%402x.png?alt=media)

Mentre aggiungi articoli al budget, questo si trova in uno stato temporaneo e non valido perché l'importo totale non è stato aggiornato per riflettere gli articoli appena aggiunti. Leggere l'importo totale durante il processo di aggiunta di un articolo ti fornisce informazioni errate.

Questo esempio dimostra anche una difficoltà che potresti incontrare quando risolvi un accesso in conflitto alla memoria: a volte ci sono più modi di risolvere il conflitto che producono risposte diverse, e non è sempre ovvio quale risposta sia corretta. In questo esempio, a seconda che tu volessi l'importo totale originale o l'importo totale aggiornato, la risposta corretta potrebbe essere $5 oppure $320. Prima di poter risolvere l'accesso in conflitto, devi determinare che cosa doveva fare.

{% hint style="info" %}
**Nota:** Se hai scritto codice concorrente o multithread, l'accesso in conflitto alla memoria potrebbe essere un problema che conosci. Tuttavia, l'accesso in conflitto di cui si parla qui può verificarsi su un singolo thread e *non* coinvolge codice concorrente o multithread.

Se hai un accesso in conflitto alla memoria dall'interno di un singolo thread, Swift garantisce che otterrai un errore in fase di compilazione o in fase di esecuzione. Per il codice multithread, usa il [Thread Sanitizer](https://developer.apple.com/documentation/xcode/diagnosing_memory_thread_and_crash_issues_early) per aiutarti a rilevare gli accessi in conflitto tra thread.
{% endhint %}

### Caratteristiche dell'accesso alla memoria <a href="#caratteristiche-dellaccesso-alla-memoria" id="caratteristiche-dellaccesso-alla-memoria"></a>

Ci sono tre caratteristiche dell'accesso alla memoria da considerare nel contesto degli accessi in conflitto: se l'accesso è una lettura o una scrittura, la durata dell'accesso, e la posizione in memoria a cui si accede. Nello specifico, si verifica un conflitto se hai due accessi che soddisfano tutte le condizioni seguenti:

* Gli accessi non sono entrambi letture, e non sono entrambi atomici.
* Accedono alla stessa posizione in memoria.
* Le loro durate si sovrappongono.

La differenza tra un accesso in lettura e uno in scrittura è di solito ovvia: un accesso in scrittura modifica la posizione in memoria, mentre un accesso in lettura no. La posizione in memoria si riferisce a ciò a cui si sta accedendo — per esempio, una variabile, una costante o una proprietà. La durata di un accesso alla memoria è istantanea oppure a lungo termine.

Un accesso è *atomico* se è una chiamata a un'operazione atomica su [`Atomic`](https://developer.apple.com/documentation/synchronization/atomic) o [`AtomicLazyReference`](https://developer.apple.com/documentation/synchronization/atomiclazyreference), oppure se usa soltanto operazioni atomiche del C; altrimenti è non atomico. Per un elenco delle funzioni atomiche del C, vedi la pagina man `stdatomic(3)`.

Un accesso è *istantaneo* se non è possibile che altro codice venga eseguito dopo che quell'accesso è iniziato ma prima che sia terminato. Per loro natura, due accessi istantanei non possono verificarsi nello stesso momento. La maggior parte degli accessi alla memoria è istantanea. Per esempio, tutti gli accessi in lettura e in scrittura del listato di codice seguente sono istantanei:

```swift
func oneMore(than number: Int) -> Int {
    return number + 1
}

var myNumber = 1
myNumber = oneMore(than: myNumber)
print(myNumber)
// Stampa "2".
```

Tuttavia, esistono diversi modi di accedere alla memoria, chiamati accessi *a lungo termine*, che si estendono durante l'esecuzione di altro codice. La differenza tra un accesso istantaneo e un accesso a lungo termine è che è possibile che altro codice venga eseguito dopo che un accesso a lungo termine è iniziato ma prima che sia terminato, il che è chiamato *sovrapposizione*. Un accesso a lungo termine può sovrapporsi ad altri accessi a lungo termine e ad accessi istantanei.

Gli accessi sovrapposti compaiono principalmente nel codice che usa parametri in-out in funzioni e metodi o metodi mutating di una struttura. I tipi specifici di codice Swift che usano accessi a lungo termine sono discussi nelle sezioni seguenti.

## Accesso in conflitto ai parametri in-out <a href="#accesso-in-conflitto-ai-parametri-in-out" id="accesso-in-conflitto-ai-parametri-in-out"></a>

Una funzione ha un accesso in scrittura a lungo termine a tutti i suoi parametri in-out. L'accesso in scrittura per un parametro in-out inizia dopo che tutti i parametri non in-out sono stati valutati e dura per l'intera durata di quella chiamata di funzione. Se ci sono più parametri in-out, gli accessi in scrittura iniziano nello stesso ordine in cui compaiono i parametri.

Una conseguenza di questo accesso in scrittura a lungo termine è che non puoi accedere alla variabile originale passata come in-out, anche se le regole di ambito e il controllo degli accessi altrimenti lo consentirebbero — qualsiasi accesso all'originale crea un conflitto. Per esempio:

```swift
var stepSize = 1

func increment(_ number: inout Int) {
    number += stepSize
}

increment(&stepSize)
// Errore: accessi in conflitto a stepSize.
```

Nel codice qui sopra, `stepSize` è una variabile globale, ed è normalmente accessibile dall'interno di `increment(_:)`. Tuttavia, l'accesso in lettura a `stepSize` si sovrappone all'accesso in scrittura a `number`. Come mostrato nella figura seguente, sia `number` sia `stepSize` si riferiscono alla stessa posizione in memoria. Gli accessi in lettura e in scrittura si riferiscono alla stessa memoria e si sovrappongono, producendo un conflitto.

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FqFKvdTH0ueNNQvjudleO%2Fmemory_increment%402x.png?alt=media)

Un modo per risolvere questo conflitto è creare una copia esplicita di `stepSize`:

```swift
// Crea una copia esplicita.
var copyOfStepSize = stepSize
increment(&copyOfStepSize)

// Aggiorna l'originale.
stepSize = copyOfStepSize
// stepSize ora vale 2
```

Quando crei una copia di `stepSize` prima di chiamare `increment(_:)`, è chiaro che il valore di `copyOfStepSize` viene incrementato della dimensione del passo corrente. L'accesso in lettura termina prima che inizi l'accesso in scrittura, quindi non c'è alcun conflitto.

Un'altra conseguenza dell'accesso in scrittura a lungo termine ai parametri in-out è che passare una singola variabile come argomento per più parametri in-out della stessa funzione produce un conflitto. Per esempio:

```swift
func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // OK
balance(&playerOneScore, &playerOneScore)
// Errore: accessi in conflitto a playerOneScore.
```

La funzione `balance(_:_:)` qui sopra modifica i suoi due parametri per dividere equamente il valore totale tra di essi. Chiamarla con `playerOneScore` e `playerTwoScore` come argomenti non produce un conflitto — ci sono due accessi in scrittura che si sovrappongono nel tempo, ma accedono a posizioni diverse in memoria. Al contrario, passare `playerOneScore` come valore per entrambi i parametri produce un conflitto perché tenta di eseguire due accessi in scrittura alla stessa posizione in memoria nello stesso momento.

{% hint style="info" %}
**Nota:** Poiché gli operatori sono funzioni, anch'essi possono avere accessi a lungo termine ai loro parametri in-out. Per esempio, se `balance(_:_:)` fosse una funzione operatore chiamata `<^>`, scrivere `playerOneScore <^> playerOneScore` produrrebbe lo stesso conflitto di `balance(&playerOneScore, &playerOneScore)`.
{% endhint %}

## Accesso in conflitto a self nei metodi <a href="#accesso-in-conflitto-a-self-nei-metodi" id="accesso-in-conflitto-a-self-nei-metodi"></a>

Un metodo mutating di una struttura ha accesso in scrittura a `self` per la durata della chiamata al metodo. Per esempio, considera un gioco in cui ogni giocatore ha una quantità di salute, che diminuisce quando subisce danni, e una quantità di energia, che diminuisce quando usa abilità speciali.

```swift
struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth
    }
}
```

Nel metodo `restoreHealth()` qui sopra, un accesso in scrittura a `self` inizia all'inizio del metodo e dura finché il metodo non restituisce il controllo. In questo caso, non c'è altro codice all'interno di `restoreHealth()` che possa avere un accesso sovrapposto alle proprietà di un'istanza di `Player`. Il metodo `shareHealth(with:)` qui sotto accetta un'altra istanza di `Player` come parametro in-out, creando la possibilità di accessi sovrapposti.

```swift
extension Player {
    mutating func shareHealth(with teammate: inout Player) {
        balance(&teammate.health, &health)
    }
}

var oscar = Player(name: "Oscar", health: 10, energy: 10)
var maria = Player(name: "Maria", health: 5, energy: 10)
oscar.shareHealth(with: &maria)  // OK
```

Nell'esempio qui sopra, chiamare il metodo `shareHealth(with:)` affinché il giocatore di Oscar condivida la salute con il giocatore di Maria non causa un conflitto. C'è un accesso in scrittura a `oscar` durante la chiamata al metodo perché `oscar` è il valore di `self` in un metodo mutating, e c'è un accesso in scrittura a `maria` per la stessa durata perché `maria` è stata passata come parametro in-out. Come mostrato nella figura seguente, accedono a posizioni diverse in memoria. Anche se i due accessi in scrittura si sovrappongono nel tempo, non sono in conflitto.

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FKa1htcV7OuEqOIaJbe6W%2Fmemory_share_health_maria%402x.png?alt=media)

Tuttavia, se passi `oscar` come argomento a `shareHealth(with:)`, si verifica un conflitto:

```swift
oscar.shareHealth(with: &oscar)
// Errore: accessi in conflitto a oscar.
```

Il metodo mutating ha bisogno di un accesso in scrittura a `self` per la durata del metodo, e il parametro in-out ha bisogno di un accesso in scrittura a `teammate` per la stessa durata. All'interno del metodo, sia `self` sia `teammate` si riferiscono alla stessa posizione in memoria — come mostrato nella figura seguente. I due accessi in scrittura si riferiscono alla stessa memoria e si sovrappongono, producendo un conflitto.

![](https://3581893755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNzatREGwodw9Z93LQYJb%2Fuploads%2FHDzYf2E80Hwoou0qxgLC%2Fmemory_share_health_oscar%402x.png?alt=media)

## Accesso in conflitto alle proprietà <a href="#accesso-in-conflitto-alle-proprieta" id="accesso-in-conflitto-alle-proprieta"></a>

Tipi come strutture, tuple ed enumerazioni sono costituiti da singoli valori componenti, come le proprietà di una struttura o gli elementi di una tupla. Poiché questi sono tipi valore, mutare una qualsiasi parte del valore muta l'intero valore, il che significa che un accesso in lettura o in scrittura a una delle proprietà richiede un accesso in lettura o in scrittura all'intero valore. Per esempio, accessi in scrittura sovrapposti agli elementi di una tupla producono un conflitto:

```swift
var playerInformation = (health: 10, energy: 20)
balance(&playerInformation.health, &playerInformation.energy)
// Errore: accesso in conflitto alle proprietà di playerInformation.
```

Nell'esempio qui sopra, chiamare `balance(_:_:)` sugli elementi di una tupla produce un conflitto perché ci sono accessi in scrittura sovrapposti a `playerInformation`. Sia `playerInformation.health` sia `playerInformation.energy` vengono passati come parametri in-out, il che significa che `balance(_:_:)` ha bisogno di un accesso in scrittura a entrambi per la durata della chiamata di funzione. In entrambi i casi, un accesso in scrittura all'elemento della tupla richiede un accesso in scrittura all'intera tupla. Ciò significa che ci sono due accessi in scrittura a `playerInformation` con durate che si sovrappongono, causando un conflitto.

Il codice seguente mostra che lo stesso errore compare per accessi in scrittura sovrapposti alle proprietà di una struttura memorizzata in una variabile globale.

```swift
var holly = Player(name: "Holly", health: 10, energy: 10)
balance(&holly.health, &holly.energy)  // Errore
```

In pratica, la maggior parte degli accessi alle proprietà di una struttura può sovrapporsi in modo sicuro. Per esempio, se la variabile `holly` nell'esempio qui sopra viene cambiata in una variabile locale anziché globale, il compilatore può dimostrare che l'accesso sovrapposto alle proprietà memorizzate della struttura è sicuro:

```swift
func someFunction() {
    var oscar = Player(name: "Oscar", health: 10, energy: 10)
    balance(&oscar.health, &oscar.energy)  // OK
}
```

Nell'esempio qui sopra, la salute e l'energia di Oscar vengono passate come i due parametri in-out di `balance(_:_:)`. Il compilatore può dimostrare che la sicurezza della memoria è preservata perché le due proprietà memorizzate non interagiscono in alcun modo.

La restrizione contro l'accesso sovrapposto alle proprietà di una struttura non è sempre necessaria per preservare la sicurezza della memoria. La sicurezza della memoria è la garanzia desiderata, ma l'accesso esclusivo è un requisito più rigoroso della sicurezza della memoria — il che significa che del codice può preservare la sicurezza della memoria, anche se viola l'accesso esclusivo alla memoria. Swift consente questo codice sicuro per la memoria se il compilatore può dimostrare che l'accesso non esclusivo alla memoria è comunque sicuro. Nello specifico, può dimostrare che l'accesso sovrapposto alle proprietà di una struttura è sicuro se si verificano le condizioni seguenti:

* Stai accedendo solo a proprietà memorizzate di un'istanza, non a proprietà calcolate o a proprietà di classe.
* La struttura è il valore di una variabile locale, non di una variabile globale.
* La struttura non è catturata da alcuna closure, oppure è catturata solo da closure non-escaping.

Se il compilatore non può dimostrare che l'accesso è sicuro, non consente l'accesso.
