mikrocontroller.net

Forum: PC-Programmierung versteh das mit const nicht


Autor: hausmeister krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
es geht um c++

wann muss ich da const verwenden gibts da regeln? ich hab in einem

anderen theard ja schon mal beschrieben das der const einfach weggecatet
wurde! also wann mus ich das verwenden?

Autor: Sachich Nich (dude) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal solltest du was an deiner Sprache machen, sonst wirst du hier im 
Forum auch ganz schnell "weggecatet".

Autor: TL431 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hausmeister krause schrieb:
> es geht um c++
>
> wann muss ich da const verwenden gibts da regeln? ich hab in einem
>
> anderen theard ja schon mal beschrieben das der const einfach weggecatet
> wurde! also wann mus ich das verwenden?

Ist doch einfach.
Verändert sich etwas nicht, ist es also in einem gewissen Zusammenhang 
als konstant anzusehen, dann machst du es const.
Wenn Werte an Funktionen per Value übergeben werden, kannst du dir das 
const sparen, da die Funktion ja sowieso ihre eigene Kopie erhält, die 
sie nach Herzenslust verändern darf.
Aber abgesehen davon ist const ganz einfach die Zusicherung an den 
Aufrufer einer Funktion: Das was du mir gibst werde ich nicht verändern.

Bsp.

int foo( const char* string );

Die Funktion foo übernimmt einen Pointer auf eine Zeichenfolge. Und sie 
gibt die Zusicherung, dass sie die Zeichenfolge nicht verändern wird. In 
so eine Funktion kann man also bedenkenlos ein Stringliteral hineingeben

int main()
{
  foo( "Hallo world" );
}

weil foo die Zusicherung macht, sich nicht am String selbst zu 
vergreifen und ihn zu ändern (was bei Stringliteralen fatal wäre).

Autor: hausmeister krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich zb. das hier habe

const *zeichenkette = "ichbinvolltoll";

wie muss ich jetzt das an ne Funktion Übergenen?

Autor: hausmeister krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
const char *zeichenkette = "ichbinvolltoll";



String(const char * = "");

muss ich dann da dieses CONST vor char angeben

Autor: hausmeister krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bei meinem Programm geht das auch ohne const

const char *zeichenkette = "ichbinvolltoll";



String(char * = "");

Autor: Mikke Mikke16 (hausmeister)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl heinz Buchegger
hab dir mal den kompletten Code per pn geschickt

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hausmeister krause schrieb:
> Wenn ich zb. das hier habe
>
> const *zeichenkette = "ichbinvolltoll";
>
> wie muss ich jetzt das an ne Funktion Übergenen?
int main()
{
   foo( zeichenkette );
}

wahnsinnig schwer, gell :-)

Der Aufrufer braucht überhaupt nichts tun. Der übergibt seine Argumente, 
so wie bisher auch, an die Funktion.
const ist die Zusicherung der Funktion an den Aufrufer: das was du mir 
gibst - ich werde es nicht verändern. Wenn das übergebene beim Aufrufer 
selbst const ist, dann ist diese Zusicherung wichtig. Wenn es das nicht 
ist, dann ist die Zusicherung egal.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hausmeister krause schrieb:
> const char *zeichenkette = "ichbinvolltoll";
>
>
>
> String(const char * = "");
>
> muss ich dann da dieses CONST vor char angeben

Die erste Frage ist immer:
Was macht die Funktion mit dem Übergebenen?
Ändert sie das Übergebene oder tut sie das nicht?

Wenn sie das Übergabeargument versucht zu verändern, dann kann das 
Übergabeargument nicht const sein (sollte eigentlich logisch sein).

Ein String Literal ist immer const!

Daher kann diese von dir skizzierte Funktion den übergebenen String 
schon nicht modifizieren. Ergo macht man das Argument const.

Stell es dir so vor:
Dein Freund gibt dir ein Buch. Du sicherst ihm zu: Ich werde nichts in 
das Buch hineinschreiben (Das Buch ist für dich const). Wenn er dir eine 
Handschrift aus dem 14. Jahrhundert gibt, dann ist diese Zusicherung für 
ihn wichtig. Wenn er dir aber einen Schmierblock gibt, dann wird es ihn 
kaum jucken, wenn du ihm zusicherst, nichts hineinzuschreiben. Du 
könntest, wenn du wolltest, aber da du ohnehin nicht willst ....

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hausmeister krause schrieb:
> bei meinem Programm geht das auch ohne const
>
> const char *zeichenkette = "ichbinvolltoll";
>
>
>
> String(char * = "");

Ja, das ist leider ein Zugeständnis an die Entwicklungsgeschichte von C 
und C++. Das heist trotzdem nicht, dass es korrekt ist.
Richtig ist:
ein String Literal ist immer const.
Einen const Pointer kann man nicht an einen nicht const Pointer 
zuweisen.

Soweit zur Theorie. Für const char* und char * wird explizit eine 
Ausnahme gemacht, weil sonst Unmengen an altem Code (vor allem Code der 
von C nach C++ übernommen wurde) nicht mehr compilierbare wäre. Das 
bedeutet aber nicht, dass es korrekt ist. Es ist mehr eine Ausnahme: 
"Wir erlauben das ausnahmsweise, aber die Benutzung ist auf eigene 
Gefahr"

Für neueren Code gibt es keinen Grund diese Praxis weiterzuführen. const 
korrekt programmieren kostet nichts und beugt potentiellen Fehlern vor. 
Ganz abgesehen davon, kann es dem Compiler helfen Optimierungen 
anzubringen, die sonst nicht möglich wären.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mikke Mikke16 schrieb:
> @ Karl heinz Buchegger
> hab dir mal den kompletten Code per pn geschickt

Poste ihn bitte hier

Autor: haya (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

hier noch einige Anmerkungen:

"const" verwenden im Prinzip 2 Seiten

a) Anwender/Nutzer einer Funktion:
Der kann aus der const Deklaration ersehen, dass seine Variable, die er 
an eine Funktion übergibt, nicht verändert wird.
Wenn man dann fremde Funktionen aufrufen will versteht man diese dann 
eher, weil man sieht was verändert wird - und was nicht. Die 
Dokumentation ist ja meistens nicht besonders ausführlich :-(

b) als Entwickler/Bereitsteller einer Funktion:
Als Entwickler will man sich vor eigenen Fehlern schützen. Dann passt 
eben der Compiler für einen auf, dass man keine const Variablen ändert.

Das bedeutet, dass man const Parameter nicht an andere Funktionen - ohne 
const - weitergeben darf! Da geht dann meist das Problem los, dass 
"alter" Code oder Code "von Neulingen" eben die const Angaben nicht 
enthalten ...

b-1)
dann kann der Entwickler versuchen diese Funktion entsprechend 
anzupassen, und das const dort jeweils durchziehen - wenn der Code 
bereitsteht. Aber manchmal betrifft das eben fremde Bibliotheken, wo man 
nicht ändern kann (oder will).

b-2)
Einfacher oder überhaupt durchführbar ist dann dieses "const Korsett" 
durch einen "bösen" cast beim Aufruf zu entfernen.

Wenn man "lesbar" und "sicher(er)" programmieren will, sollte man also 
möglichst viele const einsetzen. Und bei der Auswahl der einzubindenden 
Bibliotheken Vorsicht walten lassen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für C++ geht die Sache dann auf der Ebene der Member-Funktionen einer 
Klasse weiter. Auch hier wieder die Frage: Verändert eine Member 
Funktion das Objekt, für welches sie aufgerufen wurde, oder tut sie das 
nicht.

Nehmen wir als Beispiel eine Klasse, die einen Kreis repräsentiert.
Welche Member Funktionen hat die?
Da wird es eine Funktion geben, die zb den Radius des Kreises setzt bzw. 
liewfert. Und es wird Funktionen geben, die Fläche und Umfang berechnen.
class Circle
{
  public:
    Circle( double rad = 0.0 } : radius_( rad ) {}

    void radius( double rad )  { radius_ = rad; }
    double radius()            { return radius_; }

    double area()              { return radius_ * radius_ * PI; }
    double circumference()     { return 2 * radius_ * PI; }

  private:
    double radius_;
}

jetzt machen wir diese Klasse const-korrekt.
Daher die Fragestellung: Welche Funktionen kann ich aufrufen, ohne dass 
sich das Objekt verändert?

Na ganz sicher die radius() Funktion. Dadurch, dass ich einen Kreis nach 
seinem Radius frage, verändert sich der Kreis nicht. Ditto für area und 
circumference.

Was ist mit void radius( double rad )?
Rufe ich diese Funktion auf, dann verändert sich das Objekt. Ein Kreis 
mit einem Radius von 2.0 ist ein anderer als ein Kresi mit Radius 5.0

const-korrekt ist die Klasse also:
class Circle
{
  public:
    Circle( double rad = 0.0 } : radius_( rad ) {}

    void radius( double rad )    { radius_ = rad; }
    double radius() const        { return radius_; }

    double area() const          { return radius_ * radius_ * PI; }
    double circumference() const { return 2 * radius_ * PI; }

  private:
    double radius_;
}

und das wars dann schon. Jetzt ist die Klasse const korrekt.

Habe ich eine Funktion foo, die einen Kreis (zb per Referenz) erhält.
void foo( Circle & arg )
{
  arg.radius( 5.0 );
}

dann kann diese Funktion den Kreis verändern. Sagt sie ja auch selbt in 
ihrer Argumentliste: Der Kreis, den du mir gibst - Ich werde ihn 
verändern.
(Da ist kein const)

Auf der anderen Seite haben wir die Funktion bar
void bar( const Circle & arg )

Diese Funktion sagt explizit: Mach dir keine Sorgen. Der Kreis, den du 
mir übergibst - ich werde ihn nicht verändern.
Der Compiler überwacht diese Zusicherung. Machst du
void bar( const Circle & arg )
{
  arg.radius( 5.0 );
}

dann klopft dir der Compiler auf die Finger. Du hast zugesichert, arg 
nicht zu verändern. Die Funktion radius( double rad ) ist aber nicht 
const markiert. Man kann sie daher nicht aufrufen weil sie das Objekt 
verändert und es setzt eine Fehlermeldung.

Auf der anderen Seite
void bar( const Circle & arg )
{
  int Irgendwas;

  Irgendwas = arg.area() * 8.567;
}

ist völlig legal. area() trägt in der Klasse das const Attribut als 
Zusicherung, dass ein Aufruf von area() das Objekt nicht verändern wird. 
Es ist daher kein Problem diese Memberfunktion von arg aufzurufen. Die 
Zusicherung von bar an seinen Aufrufer wird dadurch nicht gebrochen. Das 
Objekt arg bleibt so wie es vor Aufruf von bar() war, auch wenn man 
zwischendurch das Objekt nach seiner Fläche befragt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.