C'è qualche ragione per non usare const anche se è possibile?

1

Recentemente ho avuto una discussione in cui sostenevamo se fosse una buona idea rendere tutto const, se possibile.

L'argomento è andato così: se espongo una parte interna della classe restituendo un riferimento non-const ad esso, non dovrei fare quel getter const anche se è possibile.

Ad esempio:

  class Foo
  {
     std::unique_ptr<int> bar;

  public:
     Foo()
        : bar{std::make_unique<int>(10)}
     {
     }

     int& getBar() const // <-- we argued about that const here
     {
        return *bar;
     }
  };

  int main()
  {
     const auto foo = Foo{};
     foo.getBar()++;
  }

Il codice dall'alto funziona solo perché int non è memorizzato nella memoria di Foo stesso. Se sostituissi unique_ptr con un normale int ma mantieni l'interfaccia pubblica della classe uguale, il compilatore emetterà un errore:

  class Foo
  {
     int bar;

  public:
     Foo()
        : bar{10}
     {
     }

     int& getBar() const
     {
        // error: binding reference of type 'int&' to 'const int' discards qualifiers
        return bar;
     }
  };

  int main()
  {
     const auto foo = Foo{};
     foo.getBar()++;
  }

È una buona idea rendere intenzionalmente una funzione getter non-const se espone qualcosa di interno alla classe come riferimento non const?

    
posta Martin 03.07.2017 - 08:23
fonte

1 risposta

9

L'interfaccia di una classe deve proteggere il suo stato interno in modo che i suoi invarianti non possano essere violati da utenti esterni. (Ovviamente, all'interno della ragione, il C ++ rende impossibile la protezione da tutte le modifiche.)

Un invariante implicito di un oggetto const è che il suo stato logico (qualunque cosa sia - la definizione di stato logico per una classe dipende dal suo autore, e potrebbe differire dai semplici valori dei suoi bit) non può cambiare.

Quindi una funzione const che consente all'utente di modificare lo stato logico è una cattiva idea, dal momento che rende facile rompere l'invariante,.

Quindi la questione se getBar() debba essere const dipende se il valore dietro il puntatore fa parte o meno dello stato logico dell'oggetto. Forse nel codice reale è un riferimento a un oggetto gestore che ha creato questo oggetto (non probabile per un unique_ptr, ma potrebbe essere in altri casi). In tal caso, restituire un riferimento non const da una funzione membro const andrebbe bene.

Ma nel caso di un unique_ptr, è più probabile che il valore dietro il puntatore faccia effettivamente parte dello stato logico, e come tale restituire un riferimento non const da una funzione const sia una cattiva idea.

    
risposta data 03.07.2017 - 10:25
fonte

Leggi altre domande sui tag