Il video che hai citato è per un pubblico avanzato ed esperto. Herb Sutter cerca di portare questo pubblico a un consenso su come migliorare comunicare l'intento di queste parole chiave ad altre persone, in questa età di tutto ciò che desidera essere thread-safe .
Quindi non aspettarti che questo video contenga tutto il necessario per scrivere codice perfettamente thread-safe.
I'm marking every private member as mutable because they're either protected by a mutex or thread-safe (by their implementation) - which doesn't feel right (I'm inexperienced and do not have a basis for this).
Ecco un esempio ipotetico di ciò che sarebbe palesemente sbagliato:
class Size
{
mutable int x;
mutable int y;
// ...
public:
void setSize(int newX, int newY) const // (first scream)
{
// modify members "x" and "y", "SAFELY!" (second scream)
}
};
La firma della funzione urla in modo errato, perché una funzione chiamata setSize
non potrebbe essere const
. L'implementazione del codice della funzione alla fine richiederebbe di contrassegnare i membri "x" e "y" come mutable
, il che farebbe anche gridare male.
Non importa quale codice è nella funzione setSize
. Se il nome della funzione implica che la funzione cambierà lo stato dell'oggetto, non dovrebbe essere contrassegnato con const
. Supponiamo di rimuovere la parola chiave const
dalla funzione. Ora scopriamo che non dobbiamo usare la parola chiave mutable
sui membri "x" e "y". Problema risolto.
In altre parole, se l'uso di const
e mutable
sono entrambi contro l'intuizione, e se tale uso imbarazzante si verifica in coppia, allora si dovrebbe essere sospettosi del fatto che il loro uso sia sbagliato.
Tuttavia, il video menziona un caso eccezionale. Se una classe contiene un membro std::mutex
, è quasi sempre corretto contrassegnarlo come membro mutable
. Si prega di fare riferimento al video per le spiegazioni.
Una volta che hai fatto esperienza nel farlo correttamente, puoi fare affidamento sul tuo intuito per vedere se sembra naturale e naturale significa correggere.
Se il nome di una funzione implica che non dovrebbe cambiare lo stato dell'oggetto, allora dovrebbe essere contrassegnato con const
, e il codice all'interno deve essere fatto thread-safe, con non che eseguono operazioni thread-safe.
Questa è la mentalità espressa nel video collegato sopra. Quando si tratta di sicurezza del thread, gli utenti del tuo codice (te stesso o i tuoi compagni di squadra) hanno certe aspettative che alcune funzioni non dovrebbero fare certe cose .
Il video menziona questi esempi:
-
bool operator == (const T& other) const
non dovrebbe mai modificare this
o other
, perché nessuno si aspetterebbe confronti per modificare qualcosa. (Questo è chiamato "effetto collaterale".)
-
class T { public: T(const T& other) {...} };
non dovrebbe mai modificare other
, perché la stessa istanza di other
potrebbe essere stata passata in due thread, ogni threading lo ha passato al costruttore di copie.
Che ne dici di questo codice?
class Size
{
const int x;
const int y;
// ...
public:
Size(int init_x, int init_y)
: x(init_x), y(init_y)
{
}
};
Questo codice è ancora migliore. Dimostra l'uso corretto di const
sui membri.
Tuttavia, impedisce a uno di utilizzare la classe Size
in determinati modi. Ad esempio, non puoi utilizzare gli operatori di assegnazione per sovrascrivere un'istanza esistente di Size
. In altre parole, seguendo la best practice quando si implementa la classe Size
, potrebbe essere necessario ridisegnare un altro codice sorgente che utilizza Size
. Questo è il "problema contagioso" che rende costanza un'importante considerazione per un progetto C ++.