2014-09-26 27 views
10

Qual è il modo corretto di gestire (altrimenti) le funzioni costanti che includono una chiamata al generatore casuale della classe a caso del C++ 11? Dovresti preferire rinunciare al flag costante della funzione o sarebbe meglio dichiarare generatore e distribuzione come elementi mutabili della tua classe? Un esempio minimo (non compilare) potrebbe essere:Corretto costante e <random>

#include <random> 

class foo 
{ 
    std::mt19937 MyGenerator; 
    std::normal_distribution<precision_type> gauss; 
    double get_rnd() const {return gauss(MyGenerator);} 
}; 
+0

Potresti pubblicare un piccolo esempio? Se l'istanza 'random' non sta tentando di mutare nessuno dei membri della classe, e non è di per sé un membro, la funzione può comunque rimanere' const'. – CoryKramer

+4

@Cyber: Sulla base della domanda sembra chiaro che l'istanza 'random' È un membro (domanda detta" elemento "). –

+3

Una considerazione potrebbe essere la sicurezza del filo. Il metodo Const è solitamente trattato come thread-safe. quindi, se la chiamata è protetta da mutex, per me sembra che sia ok per renderlo membro mutevole, altrimenti non se c'è una minima possibilità di coinvolgere il multithreading. – dewaffled

risposta

10

Dipende veramente da quale semantica fornisci all'accesso membro const.

Per le classi standard, è thread-safe per richiamare contemporaneamente membri const da più thread. I membri in uscita const che mutano un RNG lo interromperanno, a meno che l'RNG non sia completamente thread-safe (per uso non const).

Non è necessario progettare le classi allo stesso modo, ma altri sviluppatori troveranno probabilmente confuso scoprire classi che non possono essere tranquillamente "lette" (invocano le funzioni membro const) contemporaneamente.

Un'opzione consisterebbe nel fornire due varianti: una versione non const che utilizza l'RNG memorizzato internamente e una versione const che accetta un RNG mediante riferimento non const. (Il primo può chiamare il secondo, non è richiesto const_cast). Questo implementa la linea guida "paga solo per quello che ti serve" w.r.t thread-safety, poiché più thread possono tranquillamente utilizzare l'oggetto se ognuno fornisce un'istanza RNG locale thread. Consente inoltre di eseguire test utilizzando un'implementazione RGG fittizia, che è probabilmente ancora più preziosa.

+1

Fintanto che è possibile eseguire il seeding del RNG fornito dall'utente (ad esempio, il costruttore della classe consente di fornirlo), quindi il test è meno di un problema anche senza una simulazione poiché si è già deterministici. La simulazione diventa più preziosa quando si desidera che la sesta chiamata restituisca un valore specifico non restituito nel primo 5 ... –

2

La mutable parola chiave è stata progettata per questo tipo di casi. Quando contrassegni il campo dell'istanza del generatore casuale con questo modificatore, sarà consentito modificarne lo stato anche nei metodi const della classe che li include.

In generale, questa sembra essere un'area grigia a seconda del tipo di concetto rappresentato dalla classe. Se lo stato del generatore è concettualmente irrilevante per lo stato di questa classe, questa soluzione è OK. Altrimenti dovresti riconsiderare il design - se lo stato del generatore è rilevante, il metodo che lo usa non dovrebbe essere const.

+1

Direi che non è una buona idea in questo caso, però. 'mutable' è di aiuto con i metodi logicamente -const'. Il richiamo di un RNG non è logico-'const'. –

+0

@OliverCharlesworth Questo è un buon punto, tuttavia direi che è un'area grigia e dipende da quale concetto la classe sta rappresentando (ha aggiornato la risposta). – BartoszKP

+0

Suppongo che lo stesso argomento si applica a un metodo che restituisce l'ora corrente o la posizione corrente del mouse. – gnasher729

1

Penso che dipenda dal tuo caso d'uso. se si desidera un comportamento totalmente deterministico, è necessario rilasciare il flag const per assicurarsi che lo stato della classe non possa essere modificato, quindi non è previsto che venga modificato. Questo può essere importante se si scrive codice o codice rilevanti per la sicurezza che devono essere testati riproducibili.

6

tutto dipende da ciò che si vuole raggiungere, strategie tipiche includono:

  1. Esponendo mutevolezza. Semplicemente non contrassegnare il metodo come const.

  2. Esternalizzazione per esporre la mutevolezza. Passa gli elementi mutabili (qui il generatore e la distribuzione) come parametri del metodo, esponendo l'uso della mutabilità all'interno, il chiamante è responsabile per qualsiasi implicazione sulla sicurezza del thread.

  3. Implementazione della "logica" costanza.Se l'uso della casualità non è considerato come rottura della costanza logica della classe, puoi semplicemente dichiarare il generatore e la distribuzione come mutable; attenzione alle implicazioni filo di sicurezza (se necessario, cioè in un'applicazione multi-thread, utilizzare un mutex mutable)

Quale alternativa si sceglie dipende semantica si che raggiungere.

+0

In C++ si dice * Funzioni membro *;) –

+7

@BenVoigt: lo standard, di sicuro, ma colloquiale gli usi sembrano favorire i "metodi" come una mano breve :) –

+3

Il termine * metodo * ha un significato nell'informatica. Gli utenti che lo applicano indiscriminatamente in C++ provengono da Java, che * ha * metodi, e non hanno ancora capito che le funzioni dei membri C++ non sono "virtuali" per default, o programmatori di culto del carico che ripetono semplicemente ciò che ascoltano . –