Come gestire i suggerimenti da bambino a genitore?

5

Ho una classe che rappresenta un file in formato binario specifico su disco (il genitore nel titolo) e un'altra classe che rappresenta un oggetto all'interno di quel file (figlio). Quando l'oggetto cambia, a volte ha bisogno di riposizionarsi in una nuova posizione nel file e la classe del file deve essere notificata su questa nuova posizione.

Per fare ciò, ho aggiunto un campo weak_ptr all'oggetto, che punta al file. Tranne che ciò significa che ci deve essere un shared_ptr per il file, quindi sto usando un metodo factory static invece di un costruttore pubblico per questo. E l'oggetto ora non può essere inizializzato nel costruttore, quindi sto usando unique_ptr per questo.

Nel codice, assomiglia a questo:

class File;

class Object
{
private:
    std::weak_ptr<File> file;

public:
    Object(std::weak_ptr<File> file)
        : file(file)
    {}

    void modify();
};

class File
{
private:
    std::unique_ptr<Object> object;
    std::shared_ptr<File> self;

    File()
    {}

public:
    void setObjectPosition(std::uint64_t newPosition);

    static std::shared_ptr<File> create();
};

void Object::modify()
{
    std::uint64_t newPosition = …;

    file.lock()->setObjectPosition(newPosition);
}

void File::setObjectPosition(std::uint64_t objectPosition)
{
    // store objectPosition
}

std::shared_ptr<File> File::create()
{
    auto file = std::shared_ptr<File>(new File());

    file->self = file;
    file->object = std::unique_ptr<Object>(new Object(file));

    return file;
}

È questo l'approccio giusto per fare questo? O c'è una soluzione migliore / più idiomatica? Mi sembra di usare troppo *_ptr , ma non riesco a pensare a qualcosa di meglio.

    
posta svick 12.09.2013 - 20:31
fonte

2 risposte

5

Se tutto ciò che serve è un puntatore non proprietario di un oggetto, basta usare un puntatore raw. Ecco un esempio più piccolo:

template <typename T> struct binary_tree_node
{
    std::unique_ptr<binary_tree_node> left_child_;
    std::unique_ptr<binary_tree_node> right_child_;
    binary_tree_node* parent_ = nullptr;
    T data_; 
};

shared_ptr e unique_ptr implicano un qualche tipo di proprietà, che genitore figlio- non ha, dal momento che il genitore possiede il figlio. Quindi un puntatore raw è completamente a posto in questa situazione (solo non delete it!)

    
risposta data 12.09.2013 - 22:55
fonte
0

In questi casi, penso che sia meglio usare un puntatore nudo dal bambino, se non puoi garantire che il genitore che vive vive suo figlio, lascia semplicemente che il distruttore lo imposti a 0 per significare che un bambino non ha un genitore. In questo modo non hai bisogno della costruzione a 2 fasi e non paghi il sovraccarico di weak_ptr<>::lock ad ogni turno.

Probabilmente dovresti anche dare un'occhiata a boost::enable_shared_from_this<> , infatti con l'approccio che stai usando ora con File mantenendo un riferimento esplicito a se stesso, sconfiggi lo scopo di usarlo in primo luogo.

Inoltre di solito è una buona idea usare boost::make_shared<> , poiché usa entrambi un minor numero di allocazioni (risparmiando memoria e cicli), e ha solo un miglior comportamento della cache tutto intorno (dato che di solito fai il conteggio dei ref quando premi oggetto).

    
risposta data 24.09.2013 - 17:22
fonte

Leggi altre domande sui tag