it-swarm-tr.com

'Mutable' anahtar sözcüğünün, değişkenin const işlevi tarafından değiştirilmesine izin vermekten başka bir amacı var mı?

Bir süre önce, bir sınıfın üye değişkenini mutable anahtar kelimesiyle işaretleyen bazı kodlarla karşılaştım. Görebildiğim kadarıyla, bir değişkeni const yönteminde değiştirmenize izin verir:

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

Bu, bu anahtar kelimenin tek kullanımı mı, yoksa göründüğünden daha mı fazla? O zamandan beri bu tekniği bir sınıfta kullandım, boost::mutex işlevini const işlevinin iş güvenliği için kilitleme nedenleriyle kilitlemek için izin vermesini mümkün kılan işareti olarak işaretledim, ancak dürüst olmak gerekirse, bir kesmek gibi hissediyorum.

501
Rob

Bitsel const ve mantıksal const farklılaşmasını sağlar. Mantıksal yapı, bir nesnenin kilitleme örneğiniz gibi, ortak arabirimde görünür şekilde değişmediği durumdur. Başka bir örnek, ilk defa istendiğinde bir değer hesaplayan ve sonucu önbelleğe alan bir sınıf olabilir.

C++ 11 mutable bir lambda üzerinde, değer tarafından yakalanan şeylerin değiştirilebilir olduğunu göstermek için kullanılabildiğinden (varsayılan olarak değildir):

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
335
KeithB

mutable anahtar sözcüğü, nesnelerinize asdığınız const peçesini delmenin bir yoludur. Bir nesneye bir const referansınız veya işaretçiniz varsa, o nesneyi hiçbir şekilde değiştiremezsiniz hariç ne zaman ve nasıl işaretlenir mutable.

const referansınız veya işaretçiniz ile sınırlandırılmışsınız:

  • yalnızca görünür veri üyeleri için okuma erişimi
  • yalnızca const olarak işaretlenmiş yöntemleri çağırma izni.

mutable istisnası, artık mutable olarak işaretlenmiş veri üyelerini yazabilmenizi veya ayarlayabilmenizi sağlar. Dışarıdan görülebilen tek fark bu.

Dahili olarak görebileceğiniz const yöntemleri ayrıca mutable olarak işaretlenmiş veri üyelerine yazabilir. Temelde inşaat peçe kapsamlı bir şekilde deldi. mutable öğesinin const kavramını tahrip etmemesini ve yalnızca yararlı özel durumlarda kullanılmasını sağlamak tamamen API tasarımcısına bağlıdır. mutable anahtar sözcüğü, bu özel durumlara tabi veri üyelerini açıkça işaretlediği için yardımcı olur.

Uygulamada, kod tabanınız boyunca const öğesini saplantılı olarak kullanabilirsiniz (aslında kod tabanınıza const "hastalığı" ile "bulaşmak" istiyorsunuz). Bu dünyada işaretçiler ve referanslar, çok az istisna dışında const olup, mantıklı olması ve anlaşılması daha kolay olan kodlar verir. İlginç bir digression için "referans şeffaflığı" konusuna bakın.

mutable anahtar sözcüğü olmadan, sonunda izin verdiği çeşitli yararlı özel durumları ele almak için const_cast kullanmak zorunda kalacaksınız (önbellekleme, ref sayma, hata ayıklama verileri vb.). Ne yazık ki const_castmutable öğesinden çok daha fazla yıkıcıdır çünkü API client ​​kullandığı nesnelerin const korumasını imha etmeye zorlar. Ek olarak, yaygın const imha edilmesine neden olur: const_cast bir const işaretçi veya referans kullanmak, görünür üyelere aranan yazma ve yöntem çağrısı erişimine izin verir. Buna karşılık mutable, API tasarımcısının const istisnaları üzerinde ince taneli denetim gerçekleştirmesini gerektirir ve genellikle bu istisnalar özel verilerde çalışan const yöntemlerinde gizlenir.

(NB Birkaç kez veri ve yöntem görünürlük 'e atıfta bulunuyorum.Toplam veya özel olarak işaretlenmiş üyelerden bahsediyorum, tartışılan tamamen farklı bir nesne koruması türü burada .)

128
Dan L

Boost :: mutex ile kullanımınız, tam olarak bu anahtar kelimenin amaçlandığı şeydir. Başka bir kullanım, erişimi hızlandırmak için dahili sonuç önbelleklemesi içindir.

Temel olarak, 'değişken', nesnenin harici olarak görünür durumunu etkilemeyen herhangi bir sınıf niteliğine uygulanır.

Sorunuzdaki örnek kodda, made_'nin değeri harici durumu etkiliyorsa, değişken, uygun olmayan olabilir; Bölüm.

75
Frank Szczerba

Değişebilir, belirli bir özelliği const yönteminden değiştirilebilir olarak işaretlemek içindir. Bu onun tek amacı. Kullanmadan önce dikkatlice düşünün, çünkü tasarımınız mutable kullanmak yerine değiştirilirse, kodunuz muhtemelen daha temiz ve daha okunaklı olacaktır.

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

Öyleyse, yukarıdaki delilik değişken olan ne için değilse, ne için? İşte ince örnek: değişken, bir nesnenin mantıksal olarak sabit olduğu durum içindir, ancak pratikte değişmesi gerekir. Bu davalar arasında çok az sayıda ama var.

Yazarın verdiği örnekler arasında önbellekleme ve geçici hata ayıklama değişkenleri bulunur.

35
John Millikin

Önbellek gibi gizli bir iç durumun olduğu durumlarda kullanışlıdır. Örneğin:

 sınıf HashTable 
 {
 ... 
 public: 
 string araması (string key) const 
 {
 eğer (key == lastKey) 
 lastValue değerini döndürür; 
 
 string value = lookupInternal (key); 
 
 lastKey = key; 
 lastValue = değer; 
 
 dönüş değeri; 
} 
 
 private: 
 değiştirilebilir dizge lastKey, lastValue; [ .____]}.;

Ve sonra bir const HashTable nesnesinin hala iç önbelleğini değiştiren lookup() yöntemini kullanmasını sağlayabilirsiniz.

31
Adam Rosenfield

mutable, birinin sabit bir işlevdeki verileri değiştirmesine izin verdiğinize göre mevcut değil.

Amaç, nesnenin iç durumuna "hiçbir şey yapmayan" bir işleve sahip olmanız olabilir ve bu nedenle const işlevini işaretlersiniz, ancak nesne durumlarının bazılarını gerçekten donanıma göre değiştirmeniz gerekebilir. doğru işlevselliğini etkilemez.

Anahtar kelime, derleyiciye bir ipucu gibi davranabilir - teorik bir derleyici, salt okunur olarak işaretlenmiş belleğe sabit bir nesne (global gibi) yerleştirebilir. mutable varlığı, bunun yapılmaması gerektiğini ima ediyor.

Değişken verileri bildirmek ve kullanmak için bazı geçerli nedenler:

  • İplik güvenliği. Bir mutable boost::mutex ilan etmek tamamen mantıklıdır.
  • İstatistik. Bir işleve yapılan çağrı sayısının argümanlarının bir kısmı ya da tamamı verildiğinde sayılması.
  • Memoization. Bazı pahalı cevapları hesaplayın ve sonra tekrar hesaplamak yerine ileride başvurmak üzere saklayın.
8
Lloyd

Evet, öyle yapar. mantıksal olarak sınıfın durumunu değiştirmeyen yöntemlerle değiştirilmiş üyeler için kullanıyorum - örneğin, bir önbellek uygulayarak aramaları hızlandırmak için:

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;
};

Şimdi, bunu dikkatli bir şekilde kullanmalısınız - eşzamanlılık sorunları büyük bir endişe kaynağıdır; çünkü arayanlar yalnızca const yöntemleri kullanıyorlarsa iş parçacığının güvenli olduğunu varsayabilir. Ve tabii ki, mutable verisinin değiştirilmesi, nesnenin davranışını önemli ölçüde değiştirmemelidir, örneğin, diske yazılan değişikliklerin yapılması beklenirse verdiğim örnek tarafından ihlal edilebilecek bir şey Uygulamaya hemen görünür.

8
Shog9

Değişken, sınıf içinde yalnızca o sınıf içinde kullanılan, örneğin bir muteks veya kilit gibi şeyleri işaret eden bir değişkeniniz olduğunda kullanılır. Bu değişken sınıfın davranışını değiştirmez, ancak sınıfın iş parçacığı güvenliğini uygulamak için gereklidir. Bu nedenle eğer "değişken" olmadan "const" işlevlerine sahip olamazsınız, çünkü bu değişkenin dış dünya için mevcut olan tüm işlevlerde değiştirilmesi gerekecektir. Bu nedenle, bir değişkenin const işlevi tarafından bile yazılabilir hale getirilmesi için değişken eklenebilir.

Belirtilen değişken hem derleyiciyi hem de okuyucuya güvenli ve üye bir değişkenin const üye işlevi içinde değiştirilebileceği beklendiğini bildirir.

6
mkschreder

Sizin kullanımınız hack değildir, ancak C++ 'daki birçok şey gibi, mutable can geri gelmek ve yapmaması gereken bir şeyi işaretlemek istemeyen tembel bir programcı için hack olun const olmayan olarak.

4
JohnMcG

değişken, sınıfın uygulama detaylarında kullanılır. Sınıfın kullanıcısı bunun hakkında bir şey bilmek zorunda değildir, bu nedenle metodun “olması” gerektiğini düşünmektedir. Bir muteksin değişebilir olma örneğiniz iyi bir kanonik örnektir.

4
Greg Rogers

Kullanıcıya LOGICALLY vatansız olan şeyler için (ve dolayısıyla genel sınıftaki 'API'lerde "const" alıcıları olması gereken) fakat temel UYGULAMADA (.cpp kodunuzdaki) vatansız olmayan şeyler için "mutable" kullanın.

En sık kullandığım vakalar, devletsiz "düz eski veri" üyelerinin tembel başlatılması. Yani, bu tür üyelerin inşa edilmesi (işlemcisi) veya taşınması (hafızası) pahalı olduğu ve nesnenin birçok kullanıcısı onları asla istemeyeceği dar durumlarda idealdir. Bu durumda, performans için arka tarafta tembel inşaat yapmak istiyorsunuz, çünkü inşa edilen nesnelerin% 90'ı hiçbir zaman onları inşa etmek zorunda kalmayacak, yine de kamu tüketimi için doğru durumsuz API'yi sunmaya ihtiyacınız olacak.

3
Zack Yezek

Değiştirilebilirlik const in anlamını bit bitli const 'den sınıf için mantıksal const' a değiştirir.

Bu, değişken üyelere sahip sınıfların artık uzunlamasına const olduğu ve çalıştırılabilir öğelerin salt okunur bölümlerinde görünmeyeceği anlamına gelir.

Ayrıca, const üye işlevlerinin const_cast kullanmadan değişken üyeleri değiştirmesine izin vererek tip kontrolünü değiştirir.

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.
}

Daha fazla ayrıntı için diğer cevaplara bakın, ancak bunun yalnızca tip güvenliği için olmadığını ve derlenen sonucu etkilediğini vurgulamak istedim.

2
Kevin Cox

Değiştirilebilir kullandığımız en iyi örneklerden biri, derin kopyadır. kopya kurucusunda argüman olarak const &obj göndeririz. Böylece oluşturulan yeni nesne sabit tipte olacaktır. Eğer değişmek istiyorsak (çoğunlukla değişmeyiz, nadir durumlarda değişebiliriz) bu yeni oluşturulan const nesnesindeki üyelerin onu mutable olarak ilan etmemiz gerekir.

mutable storage sınıfı yalnızca bir sınıfın statik olmayan const veri üyesinde kullanılabilir. Bir sınıfın değişken veri üyesi, const olarak bildirilen bir nesnenin parçası olsa bile değiştirilebilir.

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

Yukarıdaki örnekte, üye değişkeni x'in değerini değiştirebiliriz, ancak const olarak bildirilen bir nesnenin parçasıdır. Bunun nedeni x değişkeninin değişken olarak bildirilmesidir. Ancak, y üye değişkeninin değerini değiştirmeye çalışırsanız, derleyici bir hata verecektir.

Mutable anahtar kelimesi, sınıf testi amacıyla taslaklar oluştururken çok kullanışlıdır. Bir const işlevini saplayabilir ve yine de (değişken) sayaçları veya saplamanıza eklediğiniz test işlevlerini artırabilirsiniz. Bu, inatçı sınıfın arayüzünü bozulmadan tutar.

1
Martin G

Bazı durumlarda (kötü tasarımlı yineleyiciler gibi), sınıfın bir sınıf veya diğer bazı tesadüfi bir değer tutması gerekir; bu da sınıfın ana "durumunu" gerçekten etkilemez. Bu en sık kullanılanı değiştirilebildiğim yerlerde görüyorum. Değişken olmadan, tasarımınızın bütünlüğünü feda etmek zorunda kalırsınız.

Bana da çoğu zaman bir kesmek gibi geliyor. Çok çok az durumda faydalıdır.

1
Joe Schneider

Klasik örnek (diğer cevaplarda da belirtildiği gibi) ve şu ana kadar kullanılan mutable anahtar sözcüğünü gördüğüm tek durum, önbelleğin uygulandığı karmaşık Get yönteminin sonucunu önbelleğe almak içindir. sınıftaki bir veri üyesi ve yöntemde statik bir değişken değil (birkaç işlev veya düz temizlik arasında paylaşım nedeniyle).

Genel olarak, mutable anahtar sözcüğünü kullanmanın alternatifleri genellikle yöntemde veya const_cast numarasıyla statik bir değişkendir.

Başka bir ayrıntılı açıklama burada .

1

Değişken, bir const sanal işlevini geçersiz kıldığınızda ve bu işlevdeki alt sınıf üye değişkeninizi değiştirmek istediğinizde kullanışlı olabilir. Çoğu durumda, temel sınıfın arayüzünü değiştirmek istemezsiniz, bu nedenle kendi değişken üyenizi kullanmanız gerekir.

1
Saurabh

'Mutable' anahtar sözcüğü aslında ayrılmış bir anahtar kelimedir. Sabit değişkenin değerini değiştirmek için kullanılır. Bir constsnt değerinin birden fazla değerine sahip olmak istiyorsanız, mutable anahtar sözcüğünü kullanın.

//Prototype 
class tag_name{
                :
                :
                mutable var_name;
                :
                :
               };   
0
Rajdeep Rathore