Esiste un modo standard per indicare che una funzione restituisce un nuovo puntatore?

8

A volte voglio delegare la costruzione di oggetti che una classe possiede per una funzione separata. Qualcosa come

Vertex* new_vertex(const Options& options) {
  // do stuff...
  return new Vertex(...);
}

dove la funzione è destinata a essere utilizzata all'interno di una classe che possiede Vertex . Chiaramente questa funzione può causare qualche confusione nella memoria, quindi voglio renderlo il più chiaro possibile. Esiste una convenzione di denominazione per tali funzioni?

    
posta Shep 15.07.2015 - 05:14
fonte

3 risposte

20

Restituisce unique_ptr :

std::unique_ptr<Vertex> new_vertex(const Options& options) {
  // do stuff...
  return std::make_unique<Vertex>(...);
}

Ci può essere sempre un unique_ptr che punta a un dato oggetto (a meno che non lo si abusi eseguendo il casting su Vertex* e viceversa, comunque). Non puoi mai copiare un unique_ptr , spostarlo solo. Quando una unique_ptr viene distrutta (e non è stata spostata), anche delete s l'oggetto per te.

make_unique crea un nuovo Vertex e lo avvolge in un unique_ptr ; gli argomenti che passi a make_unique sono gli argomenti che passa al costruttore.

    
risposta data 15.07.2015 - 05:20
fonte
2

Is there a standard way to indicate that a function returns a new pointer?

No, non esiste un "metodo standard" (ma esiste un criterio di progettazione dell'API attualmente considerato "best practice").

A causa di questa ambiguità ("cosa deve fare una funzione che restituisce un puntatore con esso?"), al momento è considerata best practice imporre la durata e il criterio di proprietà, attraverso il tipo restituito:

<vertex pointer type> new_vertex(const Options& options);

<vertex pointer type> può essere std::unique_ptr ("new_vertex non possiede il puntatore"), o std::shared_ptr ("il codice client non possiede il puntatore"), o qualcos'altro, che ha una semantica di proprietà chiaramente definita (ad esempio, Vertex const * const indica al codice cliente "legge l'indirizzo e i valori, ma non modifica né / non elimina il puntatore").

In generale, non si dovrebbe restituire un puntatore raw (ma in alcuni casi, "la praticità batte la purezza").

TLDR : esiste una best practice ( yes ), ma non standard (nella lingua).

Modifica :

where the function is only intended to be used to within a class that owns the Vertex

Se la classe possiede il vertice, lo scriverei in questo modo:

class SomeClass // owns the vertex
{
    void do_stuff() // uses the vertex internally
    {
        init_vertex(); // see below
        assert(vertex.get());
        // use vertex as needed
    }
private:
    // "class owns the Vertex"
    std::unique_ptr<Vertex> vertex;

    // sets the internal vertex
    // function doesn't return a pointer of any kind
    void init_vertex(const Options& options); // or "reset_", "refresh_", 
                                              // or "make_" vertex,
                                              // if the pointer can change
                                              // throughout the lifetime
                                              // of a SomeClass instance
};
    
risposta data 19.07.2015 - 11:34
fonte
0

Sì, ci sono dozzine di "standard" su questo

La risposta che consiglia unique_ptr è probabilmente la risposta migliore, ma se stai osservando i puntatori grezzi, ognuno ha sviluppato il proprio standard.

In generale le funzioni denominate create_____ o new______ o alloc_____ tendono a implicare un nuovo oggetto.

Tuttavia

Considera che stai mescolando i comportamenti. In realtà non ti importa se questa è una nuova istanza di un oggetto o meno. Ciò che ti interessa è se il chiamante è responsabile della distruzione dell'oggetto o meno. Esistono molte API che trasferiscono la responsabilità per un oggetto esistente e tali funzioni necessitano di uno schema di denominazione corrispondente. Forse give______ .

Se sei disposto ad allontanarti un po 'da C ++ ... Se sei disposto a considerare Objective-C abbastanza simile a C ++ da essere una fonte per una risposta, in realtà c'è una vera risposta in quella lingua. Objective-C gestisce la durata di vita degli oggetti usando i conteggi di riferimento. Avevano bisogno di un modo per descrivere se vi fosse stata data la responsabilità per un oggetto, o semplicemente un riferimento a un oggetto esistente. Se ottieni la risposta sbagliata, ottieni il ref-count sbagliato e perdi oggetti. Di conseguenza, hanno stabilito una regola: ogni oggetto che si restituisce è di proprietà di qualcun altro (quindi è necessario incrementare e decrementare il conteggio ref), ad eccezione delle chiamate di creazione che passano a un puntatore già incrementato (è necessario solo decrementare). Queste chiamate sono state identificate dal nome del metodo. I metodi che iniziano con alloc new copy o mutableCopy hanno sempre restituito un nuovo oggetto. Quindi, lo standard è stato applicato dalla lingua.

    
risposta data 23.12.2015 - 04:54
fonte

Leggi altre domande sui tag