Se non ci fosse stack, il limite di 16 byte per le strutture avrebbe ancora senso?

0

Dai documenti ufficiali:

AVOID defining a struct unless the type has all of the following characteristics:
[...]
It has an instance size under 16 bytes.
[...]

So che un motivo per tenerlo sotto i 16 byte è che le strutture sono pensate per essere utilizzate in pila. Tuttavia, ci sono altri motivi?

Per non creare accidentalmente un problema XY, quello che voglio sapere è:
Questa regola di 16 byte ha ancora senso in una situazione in cui utilizzo una struct come campo privato in una classe?

Tutti noi adoriamo il codice, quindi ecco un esempio:

public struct Address
{
    public readonly string Line1;
    public readonly string Line2;

    public Address(string line1, string line2)
    {
        Line1 = line1;
        Line2 = line2;
    }

}

public class Person
{
    private Address _address;

    [...]

    public void ChangeAddressLine1(string newLine1)
    {
        _address = new Address(newLine1, _address.Line2);
    }
}
    
posta Raphael Schmitz 29.12.2017 - 23:31
fonte

3 risposte

6

Preferisci le piccole strutture perché le strutture verranno probabilmente copiate e le strutture più piccole sono meno costose da copiare.

Le documenti forniscono un un po 'più contesto per quel limite di dimensione di 16 byte:

Next, reference type assignments copy the reference, whereas value type assignments copy the entire value. Therefore, assignments of large reference types are cheaper than assignments of large value types.

Assumendo una dimensione di parola di 8 byte, una struttura di 16 byte è solo due volte più grande di un puntatore a un tipo di riferimento, quindi ancora relativamente efficiente da copiare.

Questo non è completamente correlato alle dimensioni dello stack limitato. Lo stack ha in genere molto più spazio di quanto si possa pensare, a meno che non si stiano scrivendo algoritmi profondamente ricorsivi.

In C e C ++, è comune memorizzare quantità significative di dati nello stack e queste lingue hanno solo tipi di valore. Ma a differenza di C #, possono specificare se una struttura viene passata per valore (e quindi copiata), o per riferimento o puntatore (senza copia). Le linee guida del C ++ consigliano che i parametri vengano passati per riferimento, a meno che il tipo sia noto per essere efficacemente copiabile (banalmente copiabile senza invocare costruttori di copia e solo fino a due o tre parole di grandi dimensioni). In tali circostanze, una copia è più efficiente del passaggio per riferimento poiché la copia evita il puntatore indiretto.

    
risposta data 29.12.2017 - 23:47
fonte
2

I know that one reason for keeping it under 16 bytes is that structs are intended to be used on the stack.

Il modo in cui le strutture sono memorizzate in C # è un dettaglio di implementazione. Potrebbero essere memorizzate nello stack, ma potrebbero non farlo.

Does this 16 byte rule still make sense in a situation where I use a struct as a private field in a class?

Ciò che conta è se si desidera la semantica value o reference , non la dimensione assoluta della struct. Se sei disposto a sopportare la copia, le tue strutture possono essere grandi quanto vuoi. Nella maggior parte dei casi, tuttavia, ti verrà offerto un servizio migliore utilizzando le classi per tipi di dati più grandi.

Ulteriori letture
The Truth About Value Types

    
risposta data 29.12.2017 - 23:56
fonte
1

Penso che dipenda da come accedi / usi la struttura che è il membro privato dell'oggetto.

In un accesso del membro struct dall'oggetto, immediatamente seguito da un accesso struct member, l'IL seguirà direttamente questi passaggi facendolo apparire per ottenere la struct e quindi da quello il membro della struct.

Tuttavia, la JIT interpreterà questo come un approccio ai calcoli finalizzato ad accedere solo al membro della struttura. Nonostante l'istruzione IL per farlo, non caricherà / copierà l'intera struttura (ad esempio nello stack) per accedere a un campo della struttura. Pertanto, il JIT dovrebbe generalmente produrre lo stesso codice per accedere a person._address.Line1 come person.Line1 , ad es. come se i campi Line1 / Line2 fossero direttamente nell'oggetto Person .

Tuttavia, se si accede alla struct nel suo insieme senza accedere immediatamente a un membro della struct, probabilmente ne farà una copia con cui lavorare; a volte ciò è strettamente necessario ma altre volte potrebbero essere evitate.

La gestione delle strutture (come l'ottimizzazione della copia nel codice JIT) è un'area di miglioramento continuo nel JIT .NET.

    
risposta data 30.12.2017 - 02:06
fonte

Leggi altre domande sui tag