Ist der ‚wandelbar‘ Keyword hat keinen anderen Zweck als so dass der Variable durch eine konstante Funktion geändert werden?

StackOverflow https://stackoverflow.com/questions/105014

  •  01-07-2019
  •  | 
  •  

Frage

Vor einiger Zeit stieß ich auf einige Code, der eine Membervariable einer Klasse mit dem mutable Schlüsselwort gekennzeichnet. Soweit ich es einfach sehen können, können Sie eine Variable in einem const Verfahren ändern:

class Foo  
{  
private:  
    mutable bool done_;  
public:  
    void doSomething() const { ...; done_ = true; }  
};

Ist dies die einzige Verwendung dieses Schlüsselwort oder ist es mehr als das Auge? Ich habe diese Technik in einer Klasse, da verwendet wird, ein boost::mutex als wandelbar ermöglicht const Funktionen Kennzeichnung für gewinde aus Sicherheitsgründen zu sperren, aber, um ehrlich zu sein, es fühlt sich ein bisschen wie ein Hack.

War es hilfreich?

Lösung

Es ermöglicht die Differenzierung von bitweise const und logischer konst. Logische const ist, wenn ein Objekt in einer Art und Weise nicht ändern, die sichtbar durch die öffentliche Schnittstelle ist, wie Ihr Verriegelungs Beispiel. Ein weiteres Beispiel wäre eine Klasse, die einen Wert zum ersten Mal berechnet sie angefordert wird, und speichert das Ergebnis.

Da c ++ 11 mutable auf einem Lambda verwendet werden, um anzuzeigen, dass durch Wert erfasst Dinge veränderbar sind (sie sind nicht standardmäßig aktiviert):

int x = 0;
auto f1 = [=]() mutable {x = 42;};  // OK
auto f2 = [=]()         {x = 42;};  // Error: a by-value capture cannot be modified in a non-mutable lambda

Andere Tipps

Das mutable Schlüsselwort ist ein Weg, um die const Schleier Sie über Ihre Objekte drapieren zu durchbohren. Wenn Sie eine konstante Referenz oder Zeiger auf ein Objekt haben, können Sie dieses Objekt nicht in irgendeiner Weise ändern außer , wann und wie es mutable markiert ist.

Mit Ihrem const Referenz oder Zeiger, den Sie gezwungen sind, zu:

  • Nur-Lese-Zugriff auf sichtbare Datenelemente
  • Erlaubnis zu nennen nur Methoden, die als const gekennzeichnet sind.

Die mutable Ausnahme macht es so können Sie jetzt schreiben oder einen Satz Datenelemente, die mutable gekennzeichnet sind. Das ist der einzige von außen sichtbaren Unterschied.

Intern jene const Methoden, die für Sie sichtbar sind, können auch auf Datenelemente schreiben, die mutable gekennzeichnet sind. Im Wesentlichen wird die konst Schleier umfassend durchbohrt. Es ist völlig bis zu den API-Designern, dass mutable, um sicherzustellen, nicht das const Konzept zerstört und nur in besonderen Fällen sinnvoll verwendet wird. Das mutable Schlüsselwort hilft, weil es eindeutig Datenelemente markiert, die auf diesen speziellen Fällen unterliegen.

In der Praxis Sie const obsessiv im gesamten Codebasis verwenden können (Sie wollen im Wesentlichen zu „infizieren“ Ihre Code-Basis mit der const „Krankheit“). In dieser Welt sind Zeiger und Referenzen mit sehr wenigen Ausnahmen const, Code ergeben, die leichter an der Vernunft über ist und zu verstehen. Für einen interessanten Exkurs nachschlagen „referentielle Transparenz“.

Ohne mutable Stichwort werden Sie schließlich gezwungen werden const_cast zu verwenden, um die verschiedenen nützlichen Sonderfälle zu handhaben es erlaubt (Caching, ref Zählen, Debug-Daten, etc.). Leider const_cast wesentlich zerstörerischer als mutable, weil es die API Client zwingt den const Schutz der Objekte zu zerstören (s) er verwendet. Außerdem verursacht es weit verbreitet const Zerstörung: ein const Zeiger oder eine Referenz const_casting ermöglicht uneingeschränkten Schreib- und Verfahren Zugang zu sichtbaren Mitglieder aufrufen. Im Gegensatz mutable erfordert die API-Designer feinkörnige Kontrolle über die const Ausnahmen zu trainieren, und in der Regel diese Ausnahmen sind in const Methoden versteckt auf private Daten arbeiten.

(NB I bezieht sich auf Daten und Methode Sichtbarkeit ein paar Mal. Ich spreche über Mitglieder als öffentlich markiert vs. privat oder geschützt, die eine ganz andere Art von Objektschutz ist diskutiert hier .)

Ihre Nutzung mit boost :: mutex ist genau das, was dieses Schlüsselwort für soll. Eine weitere Anwendung ist für die interne Ergebnis-Caching-Speed-Zugang.

Im Grunde genommen ‚wandelbar‘ gilt für jede Klasse Attribut, das nicht den von außen sichtbaren Zustand des Objekts nicht beeinträchtigt wird.

In dem Beispielcode in Ihrer Frage, könnte wandelbar unangemessen, wenn der Wert von done_ externen Zustand beeinflusst, es hängt davon ab, was in der ...; Teil.

Veränderliche ist für die Markierung spezifischen Attribut als modifizierbar aus const Methoden. Das ist ihr einziger Zweck. Überlegen Sie genau, bevor es zu benutzen, weil der Code wahrscheinlich sauberer sein und besser lesbar, wenn Sie das Design ändern, anstatt Verwendung mutable.

http://www.highprogrammer.com/alan/rants/mutable.html

  

Also, wenn der oben Wahnsinn ist nicht das, was   wandelbar ist, was ist es? hier   der subtile Fall: wandelbar ist für die   Fall, in dem ein Objekt ist logisch   konstant, aber in der Praxis muss   Veränderung. Diese Fälle sind wenige und weit   zwischen, aber sie existieren.

Beispiele der Autor gibt Caching und temporäre Debug-Variablen enthalten.

Es ist nützlich in Situationen, in denen Sie einen internen Zustand wie ein Cache versteckt haben. Zum Beispiel:

class HashTable
{
...
public:
    string lookup(string key) const
    {
        if(key == lastKey)
            return lastValue;

        string value = lookupInternal(key);

        lastKey = key;
        lastValue = value;

        return value;
    }

private:
    mutable string lastKey, lastValue;
};

Und dann kann man ein const HashTable Objekt noch seine lookup() Methode verwenden, die den internen Cache modifiziert.

Nun, ja, das ist, was es tut. Ich benutze es für die Mitglieder, die durch Verfahren modifiziert werden, die dies nicht tun logisch , um den Zustand einer Klasse ändern - zum Beispiel, Lookups zu beschleunigen durch eine Cache-Implementierung:

class CIniWrapper
{
public:
   CIniWrapper(LPCTSTR szIniFile);

   // non-const: logically modifies the state of the object
   void SetValue(LPCTSTR szName, LPCTSTR szValue);

   // const: does not logically change the object
   LPCTSTR GetValue(LPCTSTR szName, LPCTSTR szDefaultValue) const;

   // ...

private:
   // cache, avoids going to disk when a named value is retrieved multiple times
   // does not logically change the public interface, so declared mutable
   // so that it can be used by the const GetValue() method
   mutable std::map<string, string> m_mapNameToValue;
};

Nun, müssen Sie dies mit Vorsicht verwenden - Parallelitätsprobleme sind ein großes Anliegen, als ein Anrufer annehmen könnte, dass sie Thread-sicher sind, wenn nur const Methoden. Und natürlich modifizieren mutable Daten sollten nicht auf das Verhalten des Objekts in nennenswerter Art und Weise ändern, etwas, das durch das Beispiel verletzt werden könnte, gab ich, wenn, zum Beispiel, es wurde erwartet, dass auf der Platte geschrieben Änderungen würden die sofort sichtbar App.

mutable existiert, wie Sie schließen ein, damit Daten in einer ansonsten konstanten Funktion ändern.

Die Absicht ist, dass Sie eine Funktion haben könnte, dass „nichts tut“, um den internen Zustand des Objekts, und so markieren Sie die Funktion const, aber man braucht wirklich einige der Objekte Zustand in einer Weise, die don‘zu ändern t die korrekte Funktionalität beeinflussen.

Das Schlüsselwort kann als Hinweis an die Compiler handeln - ein theoretischer Compiler ein konstantes Objekt (wie ein global) im Speicher platzieren konnte, die als schreibgeschützt markiert wurden. Das Vorhandensein von mutable deutet an, dass dies nicht getan werden sollte.

Hier sind einige gute Gründe zu erklären und veränderbare Daten zu verwenden:

  • Thread-Sicherheit. eine mutable boost::mutex Deklarieren ist durchaus sinnvoll.
  • Statistik. Zählen der Anzahl der Anrufe an eine Funktion, da einige oder alle ihrer Argumente.
  • memoization. Computing einig teure Antwort, und dann zum späteren Nachschlagen zu speichern, anstatt sie wieder neu zu berechnen.

Veränderliche wird verwendet, wenn Sie eine Variable in der Klasse, die nur innerhalb dieser Klasse verwendet wird, Dinge wie zum Beispiel eines Mutex um zu signalisieren, oder ein Schloss. Diese Variable nicht das Verhalten der Klasse zu ändern, aber es ist notwendig, um die Thread-Sicherheit von der Klasse selbst zu implementieren. Wenn also ohne „wandelbar“, würden Sie nicht in der Lage sein „const“ Funktionen zu haben, weil diese Variable in allen Funktionen geändert werden müssen, die mit der Außenwelt zur Verfügung stehen. Daher wandelbar wurde eingeführt, um eine Membervariable beschreibbaren auch durch eine konstante Funktion zu machen.

  

Der wandelbare angegeben informiert sowohl der Compiler und der Leser, dass es   zu erwarten ist sicher und dass ein Mitglied Variable innerhalb eines const modifiziert werden kann,   Memberfunktion.

wandelbar ist vor allem auf eine Implementierung Detail der Klasse verwendet. Der Benutzer der Klasse braucht nicht darüber zu wissen, deshalb Methode den er denkt, „sollte“ const sein kann. Ihr Beispiel mit einem Mutex wandelbar sein ist ein gutes kanonisches Beispiel.

Ihre Verwendung ist es nicht ein Hack, obwohl wie viele Dinge in C ++, wandelbar können sein Hack für einen faulen Programmierer, der nicht den ganzen Weg zurück gehen will und etwas markieren, sollte nicht const als nicht-const sein.

Verwenden Sie „wandelbar“, wenn für Dinge, die LOGISCH staatenlos für den Benutzer (und somit sollte „const“ Getter in der öffentlichen Klasse APIs), sind aber nicht staatenlos in der zugrunde liegenden Implementierung (der Code in Ihrer CPP).

Die Fälle Ich benutze es am häufigsten faul Initialisierung von state-less „plain old data“ Mitglieder sind. Es ist nämlich ideal in den engen Fällen, wenn solche Elemente teuer sind entweder (Prozessor) zu bauen oder sich herumtragen (Speicher) und viele Nutzer des Objekts wird nie danach fragen. In dieser Situation wollen Sie faul Bau auf dem Back-End für die Leistung, da 90% der gebauten Objekte nie, sie überhaupt bauen müssen, aber Sie müssen noch die richtige staatenlos API für die Öffentlichkeit präsentieren.

Mutable ändert die Bedeutung von const von bitweise const auf logisch const für die Klasse.

Das bedeutet, dass Klassen mit wandelbaren Mitgliedern mehr bitweise const sein und wird nicht mehr im schreibgeschützten Abschnitt der ausführbaren Datei angezeigt werden.

Darüber hinaus ändert es Typprüfung durch const Mitgliederfunktionen ermöglicht wandelbar Mitglieder zu ändern, ohne const_cast verwendet wird.

class Logical {
    mutable int var;

public:
    Logical(): var(0) {}
    void set(int x) const { var = x; }
};

class Bitwise {
    int var;

public:
    Bitwise(): var(0) {}
    void set(int x) const {
        const_cast<Bitwise*>(this)->var = x;
    }
};

const Logical logical; // Not put in read-only.
const Bitwise bitwise; // Likely put in read-only.

int main(void)
{
    logical.set(5); // Well defined.
    bitwise.set(5); // Undefined.
}

Sehen Sie andere Antworten für mehr Details, aber ich wollte betonen, dass es nicht nur für Typ-saftey ist und dass es wirkt sich das kompilierte Ergebnis.

In einigen Fällen (wie schlecht Iteratoren entworfen), muss die Klasse eine Zählung oder einen anderen zufälligen Wert halten, die nicht wirklich den großen „Staat“ der Klasse auswirkt. Dies ist am häufigsten, wo ich wandelbar gebraucht. Ohne wandelbar, würden Sie die gesamte const-ness Ihres Designs zu opfern gezwungen werden.

Es fühlt sich an wie ein Hack die meiste Zeit als auch zu mir. Nützlich in sehr wenige Situationen.

Das klassische Beispiel (wie in anderen Antworten erwähnt) und die einzige Situation, die ich das mutable Stichwort in bisher verwendeten gesehen habe, ist für das Caching des Ergebnisses eines komplizierten Get Verfahren, in dem der Cache als Daten Mitglied der implementiert ist Klasse und nicht als eine statische Variable in dem Verfahren (aus Gründen des Austausches zwischen mehreren Funktionen oder einfacher Sauberkeit).

Im Allgemeinen sind die Alternativen, die mutable Schlüsselwort verwenden, sind in der Regel eine statische Variable in der Methode oder der const_cast Trick.

Eine weitere detaillierte Erklärung ist in hier .

kann die veränderbare praktisch sein, wenn Sie eine const virtuelle Funktion überschreiben und wollen Ihr Kind Klassenvariable in dieser Funktion ändern. In den meisten Fällen würden Sie nicht die Schnittstelle der Basisklasse ändern wollen, so müssen Sie wandelbar Mitglied eigene Variable verwenden.

Das Schlüsselwort mutable ist sehr nützlich, wenn Stubs für Klasse Testzwecke zu schaffen. Sie können eine konstante Funktion Stummel und noch in der Lage sein, zu erhöhen (änderbare) Zähler oder was auch immer Testfunktionalität Sie Ihre Stub hinzugefügt haben. Dies hält die Schnittstelle der Stub-Klasse erhalten.

Eines der besten Beispiel, wo wir wandelbar verwenden ist, in tiefe Kopie. in Copykonstruktor wir const &obj als Argument senden. So wird das neue Objekt erstellt wird konstanten Typ sein. Wenn wir ändern wollen (meistens werden wir nicht ändern, in seltenen Fällen können wir ändern) die Mitglieder in diesem neu geschaffenen konstanten Objekt müssen wir es als mutable erklären.

mutable Speicherklasse kann nur auf nicht statisch nicht const Daten Mitglied einer Klasse verwendet werden. Veränderliche Daten Mitglied einer Klasse kann auch geändert werden, wenn es Teil eines Objekts ist, die als const deklariert wird.

class Test
{
public:
    Test(): x(1), y(1) {};
    mutable int x;
    int y;
};

int main()
{
    const Test object;
    object.x = 123;
    //object.y = 123;
    /* 
    * The above line if uncommented, will create compilation error.
    */   

    cout<< "X:"<< object.x << ", Y:" << object.y;
    return 0;
}

Output:-
X:123, Y:1

Im obigen Beispiel sind wir in der Lage, den Wert der Membervariable x zu verändern, auch wenn es Teil eines Objekts ist, die als const deklariert wird. Dies liegt daran, der Variable x als wandelbar erklärt. Aber wenn Sie versuchen, den Wert der Membervariable y zu ändern, Compiler einen Fehler aus.

Das sehr Keyword ‚wandelbar‘ ist eigentlich ein reservierter keyword.often es verwendet wird, um den Wert der Konstante variable.If variieren Sie mehrere Werte eines constsnt, verwenden Sie das Schlüsselwort wandelbar.

haben wollen
//Prototype 
class tag_name{
                :
                :
                mutable var_name;
                :
                :
               };   
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top