1

Ich möchte eine Art von "Anzahl-wie" mathematische Objekte (sagen wir, Elemente in einer Gruppe oder einem Ring) in C++ implementieren. Ich bin mir sicher, dass ich nicht der Einzige bin, der sich mit diesem Problem beschäftigt, daher gibt es reichlich Diskussionen darüber, was die "beste" Art ist, arithmetische Operatoren zu überlasten. Ich konnte jedoch keine befriedigenden Antworten finden (obwohl ich vielleicht zu faul war, mehr zu googeln).Was ist der "beste" Weg, arithmetische Operatoren in modernem C++ zu überladen?

Lassen Sie uns sagen, dass ich den Operator "+" für eine Klasse A. Das Problem ist, zu überlasten wollen, gibt zu viele verschiedene Überlastungen ich denken kann:

  1. operator + (const A & x, const A & y)
  2. operator + (const & A x, A y & &)
  3. operator + (A & & x, const A & y)
  4. operator + (A & & x, A & & y)
  5. A :: operator + = (const A & y) &
  6. A :: operator + = (const A & y) & &
  7. A :: operator + = (A & & y) &
  8. A :: operator + = (A & & y) & &

Erste Frage. Sind all diese Überladungen notwendig, um Operationen an Instanzen von A so effizient und so viel wie möglich wie "primitive Typen" zu machen? Ich denke, für "normale" Fälle muss rvalue-qualifizierter A :: -Operator + = nicht überlastet werden (oder sollte nicht). Ist es richtig? Ich denke alle 1-4 sind notwendig. Zum Beispiel müssen wir für den Fall 3, da x verschoben wird, keinen neuen Platz reservieren, um den Rückgabewert zu halten, und wir können den für x reservierten Zuordnungsspeicher sicher wiederverwenden. Ist es richtig?

Zweite Frage. Ich denke, dass all diese Überladungen viele Codes für die meisten dieser Fälle teilen. Wie kann ich die Code-Duplizierung minimieren, ohne Performance/etc. Gibt es spezielle Techniken/Idiome, um dies zu tun? Ich bevorzuge allgemeine und erweiterbare Methoden, falls vorhanden.

Antwort

4

Es ist nicht möglich, eine allgemeingültige Antwort zu geben, denn die Wahl des "besten" Weges erfordert eine Wertschätzung der Details der Operation.

Zum Beispiel das häufigste Muster (das ich unten gebe) ist nicht so gut für Matrix Multiplikation, weil in diesem Fall ist es am einfachsten, eine dritte Matrix zu deklarieren, die Null beginnt und liest die zwei Argumente. Sie können auch eine faule Auswertung verwenden, in welchem ​​Fall nichts davon zutrifft.

Ich würde empfehlen, sicherzustellen, dass Ihr Code die richtigen Antworten für alle Fälle gibt, und Sie können sich über Mikro-Optimierung später kümmern, sobald Ihr Programm funktioniert und sobald Sie mehr Erfahrung in der Sprache haben.


Für eine Klasse, wo die effizienteste Art und Weise + zu implementieren, ist eines der Argumente zu ändern, dann werden die folgenden zwei Fälle decken alle Anwendungen, mit der starken Ausnahme Garantie:

A& A::operator+=(A const &y) { /* modify *this using y */ ; return *this; } 
A operator+ (A x, A const& y) { x += y; return x; } 

Weitere Erklärung dazu, was der obige Code tut und warum, siehe operator overloading megathread.

In C++ 03 machte es keinen großen Unterschied, A const& x statt A x zu verwenden, aber in C++ 11 ist dies etwas optimaler für den Fall, dass das erste Argument ein Rvalue ist, weil Ressourcen jetzt sein können vom ersten Argument gestohlen.

In Bezug auf die Entscheidung, ref-Qualifikatoren auf operator+= zu verwenden. Es besteht kein Vorteil für die separate Überlastung von & und &&. Wenn Sie Leute gesehen haben, die & verwenden, ist die Logik nicht, auch zu überladen, aber einen Kompilierungsfehler für den Versuch zu geben, += auf einem rvalue zu verwenden; mit der Begründung, dass dies wahrscheinlich ein Fehler ist.

+0

Vielen Dank, obwohl es ziemlich spät ist, zurück zu antworten :) Es scheint, dass die obige Methode nicht "der" effizienteste Weg ist, da es unnötige Bewegungen geben kann, aber scheint ziemlich vernünftig. Kann ich einige Hinweise dazu finden, was ich tun soll, wenn Expression-Templates betroffen sind? Ich kenne einige Arbeiten, die für C++ 03 geschrieben wurden, aber ich habe keine Ahnung von C++ 11. Danke nochmal. –

Verwandte Themen