K
niv schrieb:
Was macht "const Typ&"
Es deklariert eine "Referenz-auf-const-Typ".
niv schrieb:
folgendes Beispiel z.B.:
void foobar(const KlasseA& data);
const KlasseA& getFoobar();
...
int main() {
KlasseA test;
foobar(test);
test = getFoobar();
}
Werden die Daten beim Aufruf von foobar intern kopiert?
Nein. 'data' wird nur ein neuer, zusätzlicher Name für das Objekt, was hinter 'test' steckt.
niv schrieb:
Oder ist das nur eine Referenz auf test? Wie perfomant ist das? Ist das guter oder schlechter Stil?
1. Ja, 2. Da passiert nix dolles, ist also relativ billig. 3. Es kommt drauf an, was Du machen willst und ist eigentlich keine Stilfrage.
niv schrieb:
Ist das Equivalent zu foobar(const KlasseA* data)?
äquivalent nicht. Aber sehr ähnlich. Das, was der Compiler auf Maschinenebene draus macht, sollte äquivalent sein. Weil data hier aber ein Zeiger ist, musst Du ihn innerhalb der Funktion ständig dereferenzieren, um auf das KlasseA-Objekt zugreifen zu können. Du kannst Dir Referenzen als automatisch dereferenzierende Zeiger vorstellen, die man nachträglich nicht mehr ändern kann. Also, folgendes ist auf Maschinenebene äquivalent:
void test1() {
int i = 23;
int &r = i;
r += 19;
}
void test2() {
int i = 23;
int *const p = &i;
*p += 19;
}
Wenn Du die Wahl zwischen "Typ", "const Typ&" bzw "Typ const&" als Funktionsparameter hast, dann solltest Du eine Referenz nur nehmen, falls entweder sizeof(Typ) "recht groß" ist oder falls Typ nicht mehr "trivial-kopierbar" ist. Beispielsweise ist std::string unter G++ ein recht kleines Objekt (4 Bytes auf einer 32-Bit PC-System). Es ist aber nicht trivial-kopierbar, da die Klasse einen benutzerdefinierten Kopierkonstruktor und Destruktor hat.
In generischem Code kann man teilweise boost::call_traits<T>::param_type als Funckions-Parameter-Typ verwenden. Das ist je nach Situation entweder "const T" oder "const T&". Ich glaube, diese Entscheidung hängt nur davon ab, ob T ein Klassentyp ist oder nicht.
Pass-by-value ist aber auch nicht sooooo schlimm und manchmal sehr nützlich auch wenn der Typ einen nicht-trivialen Kopierkonstruktor besitzt. Siehe
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
Da gibt es so einige Optimierungstricks, die explizit vom C++ Standard erlaubt werden. Beispielsweise ist folgende Funktion:
string flip(string const& x)
{
string result = x;
reverse(result.begin(),result.end());
return result;
}
nicht ganz so effizient in allen Fällen wie die hier:
string flip(string x)
{
string result;
result.swap(x);
reverse(result.begin(),result.end());
return result;
}
(einen modernen Compiler und ein schnelles swap vorausgesetzt)
Wenn Du also intern eine Kopie erzeugen musst, könnte sich die Übergabe per value lohnen. Wenn man das mit dem Kopieren dem Compiler überlässt, kann der es ggf wegoptimieren.
Im Zuge vom kommenden C++ Standard (C++11), sollte pass-by-value auch wieder etwas populärer werden. Für viele Klassen bietet sich ein schneller no-throw Move-Konstruktor an, mit dem unnötiges Kopieren reduziert werden kann.