Wenn du es nicht als Referenz oder Pointer übergeben würdest, müsste davon eine Kopie erstellt werden, was in diesem Fall total unnötig ist und nur zusätzliche Rechenleistung erfordert.
Das
const sorgt dafür, dass der String nicht geändert werden kann. In diesem Beispiel könnte man es natürlich problemlos weglassen.
Bei richtigen Programmen, mit höherer komplexität, führt sowas allerdings recht schnell zu einem riesigen "const"-"nicht-const"-Wirrwarr, jeder Menge Compilerfehler, sowie stundenlanges Debugging.
Wieso das so ist und warum man Pointer/Referenzen, wenn möglich, als const deklarieren sollte, ist als Anfänger erstmal schwer zu verstehen. Früher oder später findet man das dann auf die harte Tour raus. Ich versuch es trotzdem mal zu erklären.
Es ist ohne weiteres möglich
nicht-const zu
const zu casten, allerdings nicht umgekehrt (wenn man mal von const_cast absieht).
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
|
//nicht-const zu const:
FooBar foobar;
const FooBar* foobarPtr = foobar; //kein Problem
//const zu nicht-const
const FooBar foobar;
FooBar* foobarPtr = foobar; //Fehler
|
Und genau das, kann sehr schnell Probleme verursachen.
Stell dir z.B. folgendes Szenario vor:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include <string>
#include <iostream>
using namespace std;
void printString(string& str)
{
cout<<str<<endl;
}
class Foo
{
public:
const string& getString() const
{
str;
}
private:
string str;
};
int main()
{
Foo foo;
printString(foo.getString());
return 0;
}
|
getString() gibt eine Referenz auf den private Member
str zurück. Diese ist natürlich
const, weil
str nicht von außerhalb geändert werden soll.
Versucht man jetzt diesen String mit
printString() auszugeben, bekommt man einen Compilerfehler, da ein
const string nicht zu einem normalen
string gecastet werden kann.
Wenn man jetzt
string& zu
const string& ändert, dann würde das Programm ohne weiteres kompilieren:
|
C-/C++-Quelltext
|
1
2
3
4
|
void printString(const string& str)
{
cout<<str<<endl;
}
|
Der nächste Grund ist, dass man einer nicht konstanten Referenz keine Objekte direkt übergeben kann.
Um das besser zu erklären, nehme ich nochmal den Code von oben, leicht modifiziert, sodass
Foo diesmal keine Referenz zurück gibt, sondern eine Kopie des Strings.
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include <string>
#include <iostream>
using namespace std;
void printString(string& str)
{
cout<<str<<endl;
}
class Foo
{
public:
string getString() const
{
str;
}
private:
string str;
};
int main()
{
Foo foo;
printString(foo.getString());
return 0;
}
|
Hier bekommt man einen Compilerfehler, der besagt, dass man das string Objekt, das von
getString() geliefert wird, nicht direkt an
printString() übergeben kann.
Ändert man
string& wieder zu
const string&, funktioniert es tadellos.
Was ich an dieser Stelle allerdings noch hinzufügen muss ist, dass der Compiler von Microsoft beide Varianten problemlos kompiliert. Andere Compiler machen das nicht.
Es kann also nicht schaden const zu verwenden, auch wenn es überflüssig scheint.
Davon abgesehen, erleichtert es unter Umständen auch das Debugging und vermeidet unnötige Leichtsinnsfehler.
Angenommen man will einen String vergleichen, hat aber versehentlich = statt == geschrieben:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
|
void foobar(const std::string& str)
{
if (str = "test") //Schreibfehler
{
//was auch immer
}
}
|
In diesem Fall würde der Compiler sofort Alarm schlagen, da str konstant ist. Wäre das nicht so: Happy Debugging!
Ich denke du siehst jetzt, das es so einige Gründe gibt, weshalb man bei solchen Sachen const verwenden sollte.
Wie gesagt, früher oder später wirst du es wahrscheinlich selber merken.
mfg
Marvin