2017-01-24 6 views
0

betrachtenWie kann ein Additionsoperator für einen C++ - Klassencontainer optimiert werden?

class abc 
    { 
    public: 
    map<int,double> data; 

    abc(map<int,double> && in):data(std::move(in)){} 
    abc operator + (const abc & in) 
    { 
    auto tmp = data; 
     for(auto & itr : in.data) 
      tmp[itr.first] += itr.second; 
     return abc(std::move(tmp)); 
    } 
    }; 

ich eine bessere Umsetzung erraten

 abc operator + (const abc & in) 
    { 
     auto &tmp1 = (data.size() > in.data.size() ? data : in.data); 
     auto &tmp2 = (data.size() > in.data.size() ? in.data : data); 
     auto tmp = tmp1; 
     for(auto & itr : tmp2) 
      tmp[itr.first] += itr.second; 
     return abc(std::move(tmp)); 
    } 

könnte

Was ich erreichen möchte, dass, wenn ich eine Aussage zum Beispiel

S = A+B+C+D+E 

und angenommen, B, C und sind leer, die Kosten sollten gleich sein wie

S = A+E 

Im Wesentlichen möchte ich keine Kosten entstehen, wenn abc Typ ist Null. Gibt es einen Weg, das zu erreichen?

+1

Ja, Sie nutzen die Tatsache aus, dass Provisorien nicht bis zum Ende eines vollständigen Ausdrucks zerstört werden. Also machen Sie 'operator + (..., ...)' 'ein Proxy-Objekt, das einfach auf die Objekte verweist. Lassen Sie die Proxies mit sich selbst und Ihrem Objekt durch "Operator + (..., ...)" "begreifbar" sein. Bei der letzten Zuweisung von dem zuletzt erstellten Proxy machen Sie die Addition auf einen Schlag von allem, was die Proxys verbunden haben ... – WhiZTiM

+0

@WhiZTim könnten Sie Illustration oder Link zur Verfügung stellen, um diese Technik zu zeigen? – user6386155

Antwort

1

Ich glaube, Sie werden es besser machen mit:

abc operator + (abc lhs, const abc& rhs) // Note 'lhs' by value. 
{ 
    for(const auto & val : rhs.data) 
     lhs.data[val.first] += val.second; 
    return lhs;         // Rely on NRVO 
} 

Der Grund von Wert das Argument nehmen zu bevorzugen, ist, dass, wenn es sich um eine vorübergehende ist (wie zum Beispiel das Ergebnis A + B), dann wird es keine Notwendigkeit für eine Kopie. Der Compiler kann das Temporäre nur direkt übergeben.

bearbeiten Ein Proxy wie WhiZTiM vorgeschlagen wird viel effizienter, da es alles zu Ende aufschiebt. Es beruht auf der Tatsache, dass Provisorien nicht bis zum Ende des vollen Ausdrucks zerstört werden.

struct Proxy 
{ 
    std::vector<const abc*> values; 

    operator abc() { 
     assert(values.size() > 2); 
     abc result = *(values.back()); // Can't avoid one copy. 
     values.pop_back(); 
     for (const auto& v : values) 
      for (const auto& key_value : v->data) 
       result.data[key_value.first] += key_value.second; 

     return result; 
    } 
}; 

Proxy operator +(const abc &lhs, const abc& rhs) { 
    Proxy result; 
    result.values.push_back(&lhs); 
    result.values.push_back(&rhs); 
    return result; 
} 

Proxy operator +(Proxy lhs, const abc& rhs) { 
    lhs.values.push_back(&rhs); 
} 
Proxy operator +(const abc& lhs, Proxy rhs) { 
    rhs.values.push_back(&lhs); 
} 
Proxy operator +(Proxy lhs, const Proxy& rhs) { 
    // implementation left as an exercise for the reader. 
} 

Hinweis: Vor nicht zu einem Compiler ausgesetzt.

+0

passiert NRVO auf Funktionsargument? – user6386155

+0

Ah. Guter Punkt. Möglicherweise nicht. Es lohnt sich, die Ausgabe zu überprüfen, obwohl –

+0

'std :: move' bei der Rückkehr eine bessere Optimierung sein würde? – user6386155

Verwandte Themen