(Stile) "Buono" modo di trattare con bandiere / opzioni

2

Quindi ho visto molti metodi differenti usati per questo in librerie differenti, e voglio avere un'idea di quale possa essere preferito (o forse è una preferenza strettamente personale / caso per caso). Ad esempio, abbiamo una classe che tenta di aprire qualche file:

Metodo 1: Bool

class filepath {
  public:
    filepath(const std::string &s) : path_{s} {}
    bool is_dir() const { return is_dir_; }
    bool is_file() const { return is_file_; }
    bool is_link() const { return is_link_; }
    bool exists() const { return exists_; }

  private:
    const std::string path_;
    const bool is_dir_ = false;
    const bool is_file_ = false;
    const bool is_link_ = false;
    const bool exists_ = false;
};

if (f.exists()) { ... }

Vantaggi potenziali:

  • Simile a come agiscono molti linguaggi di livello superiore.
  • Nessuna necessità di costanti "magiche" / costanti globali.

Potenziali aspetti negativi:

  • Non proprio contiguo, potresti aver bisogno di più istruzioni if () per capire uno stato specifico
  • Può inondare la tua classe con getter e bool che possono essere o meno imballati in modo efficiente

Metodo 2: numeri interi costanti / enumerati

constexpr int FINFO_NOEXIST = -1;
constexpr int FINFO_ISFILE = 0;
constexpr int FINFO_ISDIR = 1;
constexpr int FINFO_ISLINK = 2;

class filepath {
  public:
    filepath(const std::string &s) : path_{s} {}
    int info() const { return info_; }

  private:
    const std::string path_;
    const int info_ = FINFO_NOEXIST;
};

switch (f.info()) { ... }

Vantaggi potenziali:

  • Permette di gestire ogni stato in una singola istruzione switch ()
  • Tutto viene imballato in un singolo intero
  • Permette l'astrazione, puoi creare funzioni is_xxx () che controllano il numero intero e restituiscono un bool.

Potenziali aspetti negativi:

  • La necessità di costanti globali / magiche che devono essere documentate / tracciate

Metodo 3: Bitflags

constexpr int FINFO_NOEXIST = 0x1;
constexpr int FINFO_ISFILE = 0x2;
constexpr int FINFO_ISDIR = 0x4;
constexpr int FINFO_ISLINK = 0x8;

class filepath {
  public:
    filepath(const std::string &s) : path_{s} {}
    int info() const { return info_; }

  private:
    const std::string path_;
    const int info_ = 0;
};

if (f.info() & FINFO_NOEXIST) { ... }

Simile al metodo 2, ma probabilmente preferito nei casi in cui molti flag possono essere impostati o non impostati.

    
posta ricco19 01.05.2018 - 19:59
fonte

2 risposte

4

Prenderò almeno in considerazione un'altra opzione: i campi bit.

class filepath {
public:
    filepath(const std::string &s)
        : path_{ s }
        , is_dir_{ false }
        , is_file_{ false }
        , is_link_{ false }
        , exists_{ false }
    {}

    bool is_dir() const { return is_dir_; }
    bool is_file() const { return is_file_; }
    bool is_link() const { return is_link_; }
    bool exists() const { return exists_; }

private:
    const std::string path_;
    const bool is_dir_ : 1;
    const bool is_file_ : 1;
    const bool is_link_ : 1;
    const bool exists_ : 1;
};

Questo combina la pulizia della tua prima scelta con lo stoccaggio denso e la flessibilità del terzo, senza creare un'astrazione che perde che costringe il cliente a essere consapevole di come i dati vengono archiviati.

    
risposta data 02.05.2018 - 09:18
fonte
1

Ad eccezione di alcuni casi limite, penso che sia solo una preferenza personale (o lo stile imposto dalla guida di stile aziendale / di progetto). Se potessi sceglierne uno, opterei per l'approccio bool poiché è semanticamente più chiaro.

I casi limite che considero potrebbero essere importanti (mi vengono in mente in questo momento):

  • Limitazioni della memoria: potrebbe essere necessario comprimerle il più possibile, il che significherebbe utilizzare (e combinare idealmente) flag.
  • Il numero di flag: noti che se hai bisogno di più di 32 flag (dimensione normale di un intero) sei limitato a cambiare il tipo di flag in long long o saltare l'approccio flags.
  • È possibile utilizzare più di un valore allo stesso tempo: se è possibile avere entrambe le opzioni FINFO_ISDIR e FINFO_ISLINK , stabilire una priorità tra di loro o passare agli approcci bool / bitmasks. A meno che i valori dell'enumerazione / delle costanti non siano completamente indipendenti (ad es. Maschere di bit), non è possibile utilizzarne più di uno allo stesso tempo.
risposta data 01.05.2018 - 21:07
fonte

Leggi altre domande sui tag