Domanda

dispiaciuto per una lunga domanda così, ma cerco di essere il più chiaro possibile. Questo segue in qualche modo la mia domanda precedente circa stringhe in C ++ . Sto cercando di capire come potevo tornare std :: string da una funzione senza allocazioni di memoria ridondanti, senza fare affidamento su NRVO . I motivi per cui non voglio fare affidamento su NRVO sono:

  • non è supportato dal compilatore attualmente usiamo
  • anche quando è supportata potrebbe non sempre essere attivata in modalità debug
  • potrebbe non riuscire in alcuni casi ( esempio )

Si noti che ho bisogno di una soluzione di 03 C ++ compatibile (senza C ++ 0x riferimenti rvalue così, purtroppo ...)

Il modo più semplice farlo è passaggio per riferimento e non std :: di swap, come questo

void test(std::string& res)
{
    std::string s;
    //...
    res.swap(s);
}

Ma è più naturale e spesso più comodo per ritornare al valore di passaggio per riferimento, quindi quello che voglio ottenere è questo:

std::string test()
{
    std::string s;
    //...
    return SOMETHING(s);
}

L'ideale sarebbe solo fare un swap con il "valore di ritorno", ma non vedere come fare questo in C ++. C'è auto_ptr già che si muove, invece di copia, e ho potuto effettivamente utilizzare auto_ptr<string>, ma mi piacerebbe evitare dinamicamente l'allocazione dell'oggetto stringa stessa.

La mia idea è in qualche modo "tag" un oggetto stringa che viene riconsegnato da una funzione per consentire in movimento i propri dati quando un costruttore di copia è chiamato al ritorno. Così ho finito con questo codice, che fa esattamente quello che voglio:

struct Str
{
    struct Moveable
    {
        Str & ref;
        explicit Moveable(Str & other): ref(other) {}
    };

    Str() {}
    Str(const std::string& other) : data(other) {} // copy
    Str(Moveable& other) { data.swap(other.ref.data); } // move

    Moveable Move()
    {
        return Moveable(*this);
    }

    std::string data;
};

Str test()
{
    Str s;
    //...
    return s.Move(); // no allocation, even without NRVO
}

Quindi ... fa tutto questo ha senso, o ci sono alcuni gravi problemi che mi manca? (Non sono sicuro se non v'è alcun problema di tutta la vita, per esempio). Forse avete già visto una tale idea in una libreria (libro, articolo ...), e mi potrebbe dare un riferimento ad esso?

EDIT: Come @rstevens notato, questo codice è MSVC-specifico e non si compila sotto g ++ che non fa come la temporanea non-const. Questo è un problema, ma diciamo solo assumono questa implementazione è MSVC-specifica.

È stato utile?

Soluzione

L'attuazione di usi spinta muove semantica di emulazione internamente per librerie come Boost.Thread . Si consiglia di guardare l'attuazione e fare qualcosa di simile.

Modifica non è in realtà un attivo sviluppo di una biblioteca Boost.Move , in modo da poter già iniziare ad usarlo.

Altri suggerimenti

Hai controllare questo codice su g ++?

Dal momento che si chiama Str (mobile &) con un oggetto temporaneo (quello restituito dalla s.Move ())!

Non si tratta della norma conforme e non supportata da g ++. E 'supportato da MSVC! (MS chiama questa una caratteristica ...).

Avete effettivamente determinata che il ritorno per valore è un problema di prestazioni nella vostra applicazione? Che sembra il / modo più semplice più semplice per andare, e quando si esegue l'aggiornamento a un compilatore più moderno è possibile utilizzare riferimenti rvalue.

Non posso rispondere alla domanda per quanto riguarda l'ordine di distruzione di s vs riferimento del Movable. Si potrebbe, per il compilatore, inserire il codice nei vari costruttori e distruttori di vedere ciò che l'ordine è. Anche se sembra ok mi piacerebbe ancora considerare l'utilizzo di uno dei modelli normali profilassi anche se solo per evitare la confusione del lettore e, eventualmente, rottura su un compilatore alternativo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top