2015-09-03 9 views
6

E 'appena venuto in mente che operator+ & co può operare su this per rvalues; cioè in una classe C, è possibile farlo:È ragionevole sovraccaricare gli operatori in base al qualificatore di riferimento per impedire i provvisori?

class C { 
    // ... 
    C operator-(const C& rhs) const & { 
     C result = *this; 
     result -= rhs; 
     return result; 
    } 
    C&& operator-(const C& rhs) && { 
     *this -= rhs; 
     return std::move(*this); 
    } 
}; 

Ciò impedirebbe copie semplicemente modificando i valori temporanei sul posto.

Sarebbe questo eseguire come mi aspetto? È una ottimizzazione ragionevole o il compilatore potrebbe creare un codice altrettanto veloce?

+0

Con la prima versione si può già ottenere copia ellision. Quindi non sono sicuro che sia necessario il secondo (se funziona, mi sento come se ti mordesse il culo ma potrei sbagliarmi) – Borgleader

+0

Sì, ho la sensazione che la copia di elision potrebbe portare a prestazioni simili. .. Ma non vedo come la mia versione potrebbe mordermi ancora nel culo. (Non sono sicuro, quindi, la domanda.) –

+0

Problemi di durata dell'oggetto. 'C && c = C() - some_C;' e 'c' sta penzolando. –

risposta

5

Diciamo che abbiamo appena avvolgiamo std::string e fare una versione semplificata di operator+:

struct C { 
    std::string val; 

    C&& operator+(const C& rhs) && { 
     val += rhs.val; 
     return std::move(*this); 
    } 

    std::string::iterator begin() { return val.begin(); } 
    std::string::iterator end() { return val.end(); } 
}; 

Con questo, questo funziona bene:

for (char c : C{"hello"}) { .. } 

la gamma-di espressione estenderà la durata del temporaneo, quindi stiamo bene. Tuttavia, considerare questo:

for (char c : C{"hello"} + C{"goodbye"}) { .. } 

Abbiamo efficace:

auto&& __range = C{"hello"}.operator+(C{"goodbye"}); 

Qui, non stiamo vincolante un temporaneo a un riferimento. Stiamo vincolando un riferimento. L'oggetto non ha una durata estesa perché ... non è un oggetto. Quindi abbiamo un riferimento ciondolante e un comportamento indefinito. Questo sarebbe molto sorprendente per gli utenti che ci si aspetterebbe a questo lavoro:

for (char c : std::string{"hello"} + std::string{"goodbye"}) { .. } 

che avrebbe dovuto restituire un valore:

C operator+(const C& rhs) && { 
    val += rhs.val; 
    return std::move(*this); 
} 

che risolve questo problema (come ora abbiamo proroga temporanea), e se spostando i tuoi oggetti è più economico che copiarli, questa è una vittoria.

Problemi correlati