C ++ restituisce oggetti persistenti

7

Attualmente sto cercando di imparare le migliori pratiche in C ++ dopo essere passato da uno sfondo C #. Capisco che ci sono tre modi per gestire gli oggetti:

  • Per valore (gli oggetti vengono copiati o spostati quando si passa dentro e fuori le funzioni)
  • Per riferimento
  • Tramite un puntatore condiviso o univoco (i puntatori non elaborati vengono disapprovati a meno che non siano realmente necessari)

In generale, ritengo che sia una buona pratica evitare di utilizzare i puntatori condivisi ma, mentre sto sviluppando molto codice di recente, sto scoprendo che inizialmente definisco qualcosa come un tipo di valore e poi finisco per doverlo rendere condiviso puntatore. Questa situazione si verifica così frequentemente che quasi tutti gli oggetti nel mio sistema si trovano in un puntatore condiviso! Questo sembra sbagliato.

La maggior parte delle mie classi assomiglia un po 'a questa:

class Container
{
public:
    // ...other functions

    std::shared_ptr<Thing> GetThing() const;
    std::vector<std::shared_ptr<Thing>> GetThings() const;

private:
    std::shared_ptr<Thing> thing;
    std::vector<std::shared_ptr<Thing>> things;
}

Inizialmente questa classe avrebbe contenuto oggetti valore di tipo Thing, ma poi altre classi hanno bisogno di accedere a questi oggetti e quindi per evitare di copiarli quando vengono restituiti dalle funzioni 'getter' li ho messi in puntatori condivisi. Ciò significa che se si verificano modifiche a questi oggetti, il loro stato sarà coerente con il contenitore e gli oggetti che attualmente accedono alle "cose".

Perché questo sembra sbagliato e come posso migliorare questo approccio? Qual è il modo corretto di fare questo in C ++?

    
posta innova 22.10.2015 - 17:09
fonte

3 risposte

6

Non è chiaro cosa fai con questi oggetti.

Se vuoi copiare la classe non copiabile, allora usare shared_ptr va bene come hai fatto.

Se vuoi copiare oggetti, quindi restituire un valore.

Se desideri solo fornire l'accesso a tali oggetti, utilizza i riferimenti:

class Container
{
public:
    // ...other functions

    const Thing& GetThing() const;
    const std::vector<Thing>& GetThings() const;

private:
    Thing thing;
    std::vector<Thing> things;
};
    
risposta data 22.10.2015 - 17:40
fonte
2

Restituisce / passa da const ref prima di passare a shared_ptr . Ti lasciano passare per riferimento senza consentire loro di cambiare l'oggetto. Ciò richiede che tu abbia cura di mantenere costante la costituttezza.

class Container
{
public:
    // ...other functions

    const Thing& GetThing() const;
    Thing& GetThing();

    const std::vector<Thing>& GetThings() const;
    std::vector<Thing>& GetThings();

private:
    Thing thing;
    std::vector<Thing> things;
}

Ciò che è importante è il ragionamento sulla proprietà. Con il valore per negozio e il pass-by-reference sai esattamente cosa possiede l'oggetto e sai chi è responsabile della sua distruzione.

    
risposta data 22.10.2015 - 17:36
fonte
1

Sembra che tu stia facendo questo perché vuoi modificare i valori interni in Container . Quindi stai facendo qualcosa del tipo:

void foo(Container &container) {
   container.GetThing().SetFoo(12);
}

Il problema è che non dovresti modificare lo stato interno di Container in questo modo. Solo i metodi su Container dovrebbero modificarlo. Quindi questa funzione dovrebbe probabilmente essere un metodo insider Container.

void Container::foo() {
    thing.SetFoo(12);
}

Se devi davvero modificare le cose al di fuori di Container , dovresti preferire qualcosa di più esplicito:

void foo(Container &container) {
    Thing thing = container.GetThing();
    thing.SetFoo(12);
    container.SetThing(thing);
}

Ma avere i metodi Get / Set per i pezzi di stato interni in Container è un odore di codice. Ti suggerisce di avere altro codice che dovrebbe essere parte di Container .

    
risposta data 22.10.2015 - 17:55
fonte

Leggi altre domande sui tag