Mitglied Zuordnung in einer konstanten Funktion
-
22-09-2019 - |
Frage
Ich habe eine Klasse Mitglied MyMember , die ein ist myType Zeiger. Ich möchte dieses Element in einer Funktion zuweisen, die als const deklariert wird. Ich mache wie folgt:
void func() const
{
...
const_cast<myType*>(myMember) = new myType();
...
}
Des Tun funktioniert gut in VC ++, aber GCC gibt einen Fehler mit der Meldung „L-Wert als linker Operand Zuordnung erforderlich“.
Making the member wandelbar erlauben Sie mir einfach die const_cast zu entfernen und den Wert zuweisen. Allerdings bin ich nicht ganz sicher, dass das kommt mit anderen Nebenwirkungen.
Kann ich mein Mitglied zuweisen, ohne das Element wandelbar machen zu müssen? Wie? Gibt es Nebenwirkungen bei der Herstellung von Mitgliedern wandelbar?
Lösung
Der Code würde nicht wirklich Arbeit in VC ++ - Sie nicht den Wert zu aktualisieren (oder zumindest es sollte nicht), also die Warnung von GCC. Korrekter Code ist
const_cast<myType*&>(myMember) = new myType();
oder [von anderer Antwort, danke: P]:
const_cast<ThisType*>(this)->myMember = new myType();
Machen Mutable es effektiv bedeutet, dass Sie impliziten const_cast
s in const
Member-Funktionen zu erhalten, die in der Regel ist das, was Sie Lenkung sein soll, wenn Sie finden sich viele const_cast
s auf this
tun. Es gibt keine ‚Nebenwirkungen mit wandelbar‘ andere als das.
Wie Sie aus den heftigen Debatten kreisen diese Frage sehen können, nolens volens Nutzung von mutable
und viele const_cast
s kann definitiv Symptome schlecht riecht in Ihrem Code. Aus konzeptioneller Sicht Wegwerfen Konstantheit oder mutable
verwenden, können viel größere Auswirkungen haben. In einigen Fällen das Verfahren auf nicht-const, das heißt, die richtige Sache zu tun sein kann auf die Tatsache, besitzt bis zu ändern, dass sie Zustand zu ändern.
Es hängt alles davon ab, wie viel const-Korrektheit Angelegenheiten in Ihrem Kontext - Sie möchten nicht nur sprinking mutable
herum wie Feenstaub zu machen Sachen Arbeit beenden, aber mutable
ist für den Gebrauch bestimmt, wenn das Mitglied ist nicht Teil des beobachtbaren Zustand des Objekts. Die strengste Ansicht von const-Korrektheit halten würde, dass kein einziges Bit den Zustand des Objekts kann geändert werden (zB dies von entscheidender Bedeutung sein könnte, wenn Sie beispielsweise in einem ROM ist ...) - in diesen Fällen müssen Sie nicht jede Konstantheit wollen verloren sein. In anderen Fällen können Sie einige externen Zustand gespeichert irgendwo ouside des Objekts haben - beispielsweise eine Thread-spezifische Cache, der auch in Betracht gezogen werden muss, bei der Entscheidung, ob es angemessen ist,
Andere Tipps
Dieses Szenario - eine gekapselte interne Zustandsänderung, die keinen externen Zustand auswirkt (z Caching Ergebnisse.) - ist genau das, was das mutable
Schlüsselwort ist für
const_cast
ist fast immer ein Zeichen von Design Versagen. In Ihrem Beispiel entweder func()
nicht const
sein sollte, oder myMember
sollte mutable
sein.
Ein Anrufer von func()
wird erwarten, dass sie nicht zu ändern Objekt; Das aber bedeutet, „nicht zu ändern in einer Weise, die sie wahrnehmen kann“; das ist nicht seine externen Zustand zu ändern. Wenn myMember
ändert nicht das externe Statusobjekt ändern, ist das, was das mutable
Schlüsselwort ist für; andernfalls func()
nicht const
sein sollte, weil Sie Ihre Funktion garantiert verraten würden.
Beachten Sie, dass mutable
ist kein Mechanismus circunvent const-Korrektheit; es ist ein Mechanismus, um es zu verbessern.
class Class{
int value;
void func()const{
const_cast<Class*>(this)->value=123;
}
};
Wie Steve Gilham schrieb, ist mutable
die korrekte (und kurz) Antwort auf Ihre Frage. Ich möchte nur einen Hinweis in eine andere Richtung geben.
Vielleicht ist es möglich, in Ihrem szenario Verwendung einer (oder mehr) Schnittstelle zu machen?
Vielleicht können Sie es aus dem folgenden Beispiel grok:
class IRestrictedWriter // may change only some members
{
public:
virtual void func() = 0;
}
class MyClass : virtual public IRestrictedWriter
{
public:
virtual void func()
{
mValueToBeWrittenFromEverybody = 123;
}
void otherFunctionNotAccessibleViaIRestrictedWriter()
{
mOtherValue1 = 123;
mOtherValue2 = 345;
}
...
}
Also, wenn Sie zu irgendeiner Funktion eines IRestrictedReader *
anstelle einem const MyClass *
passieren kann es func
nennen und damit Veränderung mValueToBeWrittenFromEverybody
während mOtherValue1
Art „const“ ist.
. Ich mutable
immer ein bisschen wie ein Hack finden (aber verwende es manchmal).