Was ist die Semantik einer const Member-Funktion?
Frage
Ich verstehe, dass die Funktion nicht erlaubt ist, den Zustand des Objekts zu ändern, aber ich dachte, dass ich irgendwo gelesen, dass der Compiler durfte davon ausgehen, dass, wenn die Funktion mit den gleichen Argumenten aufgerufen wurde, würde es den gleichen Wert zurückgeben und so könnte einen im Cache gespeicherte Wert wieder verwenden, wenn es verfügbar ist. z.
class object
{
int get_value(int n) const
{
...
}
...
object x;
int a = x.get_value(1);
...
int b = x.get_value(1);
dann könnte der Compiler den zweiten Anruf entfernt optimieren und entweder den Wert in einem Register verwenden oder einfach tun b = a;
Ist das wahr?
Lösung
const
ist über Programmsemantik und nicht um Implementierungsdetails. Sie sollten eine Memberfunktion const
markieren, wenn es, nicht den sichtbaren Zustand des Objekts ändern und sollte auf ein Objekt aufrufbar sein, der sich const
ist. Innerhalb einer const
Memberfunktion auf einer Klasse X
, die Art der this
ist X const *
: Zeiger auf konstantes X
Objekt. Somit werden alle Membervariablen innerhalb dieser Member-Funktion (außer const
sind) effektiv mutable
. Wenn Sie ein const
Objekt haben, können Sie nur const
Mitgliederfunktionen auf es nennen.
Sie können mutable
verwenden, um anzuzeigen, dass ein Mitglied Variable innerhalb einer const
Member-Funktion auch ändern kann. Dies wird normalerweise verwendet, um Variablen für die Caching Ergebnisse zur Identifizierung oder für Variablen, die den tatsächlichen beobachtbaren Zustand beeinflussen nicht wie Mutexe (Sie immer noch die Mutex in den const
Elementfunktionen sperren müssen) oder Zähler verwenden.
class X
{
int data;
mutable boost::mutex m;
public:
void set_data(int i)
{
boost::lock_guard<boost::mutex> lk(m);
data=i;
}
int get_data() const // we want to be able to get the data on a const object
{
boost::lock_guard<boost::mutex> lk(m); // this requires m to be non-const
return data;
}
};
Wenn Sie die Daten durch Zeiger nicht direkt halten (einschließlich intelligenten Zeiger wie std::auto_ptr
oder boost::shared_ptr
), dann wird der Zeiger const
in einer const
Member-Funktion, aber nicht die spitzen-to-Daten, so dass Sie das spitze ändern Daten.
Wie für das Caching: im Allgemeinen kann der Compiler dies nicht tun, weil der Staat zwischen den Anrufen ändern könnte (vor allem in meinem Multi-Threaded-Beispiel mit dem Mutex). Wenn jedoch die Definition inline ist, dann kann der Compiler den Code in die aufrufende Funktion ziehen und optimieren, was es dort zu sehen. Dies könnte in der Funktion führen effektiv nur einmal aufgerufen werden.
Die nächste Version des C ++ Standard (C ++ 0x) haben ein neues Schlüsselwort constexpr
. Funktionen getaggt constexpr
einen konstanten Wert zurück, so können die Ergebnisse zwischengespeichert werden. Es gibt Grenzen, was Sie in einer solchen Funktion (in der Reihenfolge, dass der Compiler diese Tatsache überprüfen kann) tun können.
Andere Tipps
Das Schlüsselwort wandelbar auf Membervariablen ermöglicht const Funktionen, die den Zustand des Objekts in der Hand zu verändern.
Und nein, es funktioniert nicht Cache-Daten (zumindest nicht alle Anrufe), da der folgende Code eine gültige konstante Funktion ist, die im Laufe der Zeit ändert:
int something() const { return m_pSomeObject->NextValue(); }
Beachten Sie, dass der Zeiger const sein kann, wenn die anvisierten Objekts ist nicht const, also der Aufruf von Nextvalue auf Someobject kann oder auch nicht ändern, es eigenen internen Zustand. Dies bewirkt, dass die Funktion etwas unterschiedlichen Werten jedes Mal zurück es aufgerufen wird.
Allerdings kann ich nicht beantworten, wie der Compiler mit const Methoden arbeitet. Ich habe gehört, dass es bestimmte Dinge optimieren kann, obwohl ich es aussehen müsste bis sicher sein.
Nein.
Eine const-Methode ist eine Methode, die nicht den Zustand des Objekts ändern (das heißt seine Felder), aber man kann das nicht annimmt gegeben wird, um den gleichen Eingang, Rückgabewert einer const-Methode bestimmt. Mit anderen Worten bedeutet nicht const
Schlüsselwort, dass die Funktion eine Eins-zu-eins. Zum Beispiel einer Methode, die die aktuelle Zeit zurückgibt, ist eine konstante Methode aber der Rückgabewert Änderungen zwischen den Anrufen.
Das Schlüsselwort const auf eine Member-Funktion markiert die diese Parameter als konstant. Die Funktion kann immer noch stumm globale Daten (so kann nicht zwischengespeichert werden), nicht aber Daten Objekt (so dass für Anrufe auf const-Objekten).
In diesem Zusammenhang ist eine const
Member-Funktion bedeutet, dass this
auch als const
Zeiger behandelt wird. In der Praxis bedeutet es Ihnen nicht den Zustand der this
innerhalb einer const
Elementfunktion zu ändern erlaubt.
Für no-Nebeneffekt Funktionen (dh, was Sie versuchen zu erreichen), GCC hat eine "Funktion Attribut" genannt pure
(Sie es verwenden, um __attribute__((pure))
sagen): http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
Ich bezweifle es, könnte die Funktion noch eine globale Funktion aufrufen, die den Zustand der Welt verändert und nicht verletzen konst.
Hinzu kommt die Tatsache, dass die Member-Funktion globale Daten ändern können, ist es möglich, dass die Member-Funktion zu ändern erklärt ausdrücklich wandelbar Mitglieder des Objekts in Frage.
Corey ist richtig, aber bedenken Sie, dass alle Mitgliedsvariablen, die als markiert sind wandelbar können in const Member-Funktionen geändert werden.
Es bedeutet auch, dass diese Funktionen von anderen const Funktionen aufgerufen werden können, oder über andere const Referenzen.
Edit: Verdammt, von 9 Sekunden geschlagen .... 9 !!! :)
const Methoden werden auch statische Einheimischen ändern erlaubt. Zum Beispiel (versperren und wiederholten Anrufen () werden steigende Werte zurück - nicht im Cache gespeichert 0) die folgenden ist vollkommen legal:
class Foo
{
public:
int bar() const
{
static int x = 0;
return x++;
}
};