Bringt es etwas Funktionen für const T& und T&& zu überladen?
-
Bei move-assignment wird's spannend.

-
Nathan schrieb:
Frage steht im Prinzip oben.
Bringt es einen Geschwindigkeitsvorteil, wenn man eine Funktion für L- und RValues zu überladen oder ist das egal?Das kommt drauf an. In einigen Situationen hilft es, in anderen ist es sinnfrei. std::vector<T>::push_back ist beispielsweise so überladen, weil dadurch ggf eine unnötige Kopie verhindert werden kann. Bei solchen Templates ist das sinnvoll, weil T ja nicht move-optimiert sein muss und logisch gesehen man eine "Kopie" erzeugen will. An anderen Stellen kann man das mit den Referenzen aber auch sein lassen, hier z.B.:
class dings { public: explicit dings(string s); // <-- nix mit Referenz private: string bums; ::: }; dings::dings(string s) : bums(move(s)) , ::: { ::: }Eine unnötige Kopie gibt es hier nicht, da std::string ja move-optimiert ist. Aber mit einer Überladung oder Perfect Forwarding könnte man sich noch eine ggf unnötige Move-Konstruktion sparen. Aber das lohnt sich eigentlich nicht, weil 'ne Move-Konstruktion von std::string eh recht flott ist.
-
cooky451 schrieb:
Bei move-assignment wird's spannend.

Den Zuweisungsoperator könnte man theoretisch über Pass by Value implementieren. Aber bringt das überhaupt etwas?
Solche Definitionen werden vom Compiler wahrscheinlich weder als Copy- noch Move-Assignment erkannt...
X& X::operator= (X source) { swap(source); return *this; }<
>
-
Laut Standard ist es ein copy constructor. Aber "get-value-and-swap" funktioniert halt für copy und für move. Deswegen sagte ich ja, da wird's interessant. Es ist irgendwie elegant, aber ich weiß noch nicht 100%ig was ich davon halten soll.
-
eine gute Einführung in das Thema gibt es z.B. hier:
http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html
ich habe hier mal zum Basteln ein kleines Testprogramm, viel Spaß!
#include <iostream> using namespace std; class MyInt { public: MyInt() { m_Value = 0; cout << "MyInt() "; Cout(); } MyInt(const MyInt& myCopy) { m_Value = myCopy.m_Value; cout << "MyInt(c& " << &myCopy << ") "; Cout(); } MyInt(MyInt&& myCopy) { m_Value = myCopy.m_Value; cout << "MyInt(&& " << &myCopy << ") "; Cout(); } MyInt(int i) { m_Value = i; cout << "MyInt(" << i << ") "; Cout(); } ~MyInt() { cout << "~MyInt() "; Cout(); } MyInt& operator=(const MyInt& myCopy) { m_Value = myCopy.m_Value; cout << "operator=(c& " << &myCopy << ") "; Cout(); return *this; } MyInt& operator=(MyInt&& myCopy) { m_Value = myCopy.m_Value; cout << "operator=(&& " << &myCopy << ") "; Cout(); return *this; } void setValue(int i) { m_Value = i; cout << "setValue(" << i << ") "; Cout(); } private: void Cout() { cout << m_Value << " " << this << endl; } int m_Value; }; MyInt f() { MyInt myInt; myInt.setValue(11); return myInt; } int main () { { MyInt myInt; } cout << "--- MyInt myInt;" << endl; { f(); } cout << "--- f();" << endl; { MyInt myInt(f()); } cout << "--- MyInt myInt(f());" << endl; { MyInt myInt1(7); MyInt myInt2(myInt1); } cout << "--- MyInt myInt1(7); MyInt myInt2(myInt1);" << endl; return 0; }
-
Danke, jetzt ist mir einiges klar geworden.
Ich kannte Movesemantik schon vorher, habe sie bisher aber nur benutzt und keine eigenen Beispiele geschrieben. Was Reference Collapsing etc. ist wusste ich schon vorher, aber trotzdem danke.
Ich werde in der Regel einfach foo(T obj) verwenden, nur bei großen Objekten (Container, Bilder, etc.) beide Funktionen schreiben.
lg
Nathan
-
Wie groß die Objekte sind ist dabei eigentlich eher uninteressant. (Jedenfalls wenn du vector<> für groß hälst - wenn du sizeof meinst, mein Fehler.) Da du ja movest, zählt nur wie viele Handles das Objekt hat, und wie oft die Funktion aufgerufen wird (ohne dass sie geinlined wird). Bei einem Handle auf 500MB macht's wahrscheinlich kaum einen Unterschied, bei 50 auf je 16 Byte schon.

-
Nein, ich meinte nicht sizeof.
Da fällt mir gerade was anderes ein:
Move bei Pointern ist ja im Prinzip nurptr = othr.ptr; othr.ptr = nullptr;oder?
Wie handhabst du das denn bei großen Objekten, die an Funktionen übergeben werden müssen?
-
Wie.. meinst du das jetzt? Welche Art von Groß?

-
Nathan schrieb:
Wie handhabst du das denn bei großen Objekten, die an Funktionen übergeben werden müssen?
Drück dich klarer aus. Wird der Besitz an die Funktion übergeben?
Falls ja: Klasse movable machen. Wenn das nicht geht oder immer noch teuer ist, Objekt in eine Movable-Klasse wie
std::unique_ptrstecken. In beiden Fällen Pass By Value.Falls nein: Const-Referenz wie in C++98.
-
Ich meinte Besitzübertragung.
Danke für die Erklärung Nexus.