che introduce i puntatori a un grande progetto software

2

Ho un progetto software abbastanza grande scritto in c++ .

Qui c'è un class foo che rappresenta una struttura (con cui non intendo la struttura dei programmatori) in cui foo -oggetti possono essere parte di un foo -oggetto.

Ecco class foo nella forma più semplice:

class Foo
{
    private:
        std::vector<unsigned int> indices;
    public:
        void addFooIndex(unsigned int);
        unsigned int getFooIndex(unsigned int);
};

Ogni foo -object è attualmente memorizzato in un oggetto di class bar .

class Bar
{
    private:
        std::vector<Foo> foos;
    public:
        void addFoo(Foo);
        std::vector<Foo> getFoos();
}

Quindi se un foo -object dovrebbe rappresentare una struttura con un oggetto foo "interno", al momento faccio

Foo foo;
Foo innerFoo;
foo.addFooIndex(bar.getFoos().size() - 1);
bar.addFoo(innerFoo);

E per ottenerlo, ovviamente uso:

Foo foo;
for ( unsigned int i = 0; i < foo.getFooIndices().size(); ++i )
{
    Foo inner_foo;
    assert( foo.getFooIndices().at(i) < bar.getFoos().size() );
    inner_foo = bar.getFoos().at(foo.getFooIndices().at(i));
}

Quindi questo non è un problema. Funziona e basta. Ma non è la soluzione più elegante.

Ora desidero rendere la% internafoo s "più connessa" con l'oggetto foo -object. Dovrebbe ovviamente cambiare class foo in:

class Foo
{
    private:
        std::vector<Foo*> foo_pointers;
    public:
        void addFooPointer(Foo*);
        std::vector<Foo*> getFooPointers();
};

Quindi ora, per la mia domanda: come modificare delicatamente questa classe base senza rovinare l'intero codice? C'è un "modo pulito"?

    
posta stefan 09.05.2012 - 00:46
fonte

3 risposte

1

Prenderò una pugnalata a questo.

Tutto si riduce a quale tipo di gestione della memoria desideri / hai bisogno. È possibile memorizzare i puntatori negli oggetti Foo o Foo. Dal momento che hai detto che non hai bisogno di bar , che attualmente "possiede" la memoria di Foo, ti suggerisco di metterli direttamente in Foo:

class foo
{
public:
  add_child(foo child); //Foo by value. Utilize 'move' semantics if copy is not possible.
  const std::vector<foo>& get_children(); //Get a reference to the children. Could use iterators or whatever.

private:
  std::vector<foo> foos;
}

Utilizzo:

foo parent;
foo child;
foo grand_child;
child.add_child(std::move(grand_child)); //move semantics.
parent.add_child(child);  //no move semantics.

parent.traverse(root);

void traverse(foo root)
{
    root.discombobulate_the_parafunctors(); //act on root

    auto children = root.get_children();        
    std::for_each(children.begin(), children.end(), traverse);
}

Questo è ciò che cercherò di andare avanti, ma hai detto che vuoi farlo 'delicatamente' - immagino che intendi in modo incrementale, senza rompere le cose? Poiché la proprietà viene trasferita da barra a foo nell'esempio sopra, non sarà possibile utilizzarle entrambe contemporaneamente. L'approccio puntatore, tuttavia, può essere sovrapposto all'implementazione della barra esistente.

Se volessi davvero passare "dolcemente", farei una classe chiamata qualcosa come foo_tree_view, che è come il tuo primo approccio, con i puntatori e non assume la proprietà. Lo crearei da una determinata istanza di bar e quindi usarlo nel codice client.

std::vector<foo_tree_view> bar_view;

class foo_tree_view
{
public:
  foo_tree_view(foo this_foo, bar source);
  std::vector<foo*> get_children();
private:
   ...
}

A questo punto, si inizia a modificare delicatamente tutte le posizioni per utilizzare questa nuova classe foo_tree_view. Quando tutto il codice lo usa, si passa all'implementazione di foo_tree_view per usare l'implementazione di cui sopra, senza 'bar', e rinominarlo a foo.

Spero che tu abbia un senso da questa risposta!

    
risposta data 09.05.2012 - 14:12
fonte
0

Che cosa farei:

  1. Aggiungi una variabile membro Bar * bar e int index a Foo.
  2. Hai Bar::addFoo imposta foo->bar = this e foo->index = foo.size()
  3. Implementa Foo:getFoo su Foo per utilizzare getFooIndex e bar per restituire un puntatore foo
  4. Implementa Foo:addFoo similiarmente

Quindi dovresti essere in grado di utilizzare entrambe le API contemporaneamente. Puoi deprecare le apis basate sull'indice e rimuoverle lentamente.

    
risposta data 09.05.2012 - 16:40
fonte
-2

Non penso che avere l'oggetto foo responsabile del suo indice in un contenitore sia una buona idea. Dovrebbe essere beatamente inconsapevole dei contenitori in cui si trova. Il mantenimento di questi indici è il lavoro del contenitore (se applicabile per quel contenitore).

Il tuo codice attuale richiede un foo per recuperare il foo s interno da bar quindi perché non recuperarli direttamente da foo ?

for (unsigned int index = 0; index < foo.getFooPointers().size(); ++index)
{
    Foo* inner_foo = foo.getFooPointers().at(index);
}

Perché hai bisogno del foo s interno memorizzato in bar ? Se c'è qualche situazione in cui desideri scorrere tutti i foo s, inclusi quelli interni, puoi creare un iteratore .

Come nota a margine, probabilmente chiamerei la funzione membro qualcosa come getInnerFoos() o getChildren() invece di getFooPointers() . La firma ti dice già che restituisce puntatori di tipo foo .

    
risposta data 09.05.2012 - 01:22
fonte

Leggi altre domande sui tag