1. 程式人生 > 程式設計 >聊聊C++的mutable和volatile

聊聊C++的mutable和volatile

C++中修飾資料可變的關鍵字有三個:constvolatilemutableconst比較好理解,表示其修飾的內容不可改變(至少編譯期不可改變),而volatilemutable恰好相反,指示資料總是可變的。mutablevolatile均可以和const搭配使用,但兩者在使用上有比較大差別。

mutable

mutable只能作用在類成員上,指示其資料總是可變的。不能和const 同時修飾一個成員,但能配合使用:const修飾的方法中,mutable修飾的成員資料可以發生改變,除此之外不應該對類/物件帶來副作用。

考慮一個mutable的使用場景:呼叫系統中存有司機(Driver)的資訊,為了保護司機的隱私,司機對外展現的聯絡號碼每隔五分鐘從空閒號碼池更新一次。根據需求,Driver類的實現如下虛擬碼:

class Driver {
private:
 ...
 // real phone number
 string phone;
 // display phone number
 mutable string displayPhone;

public:
 string getDisplayPhone() const {
  if (needUpdate()) {
   lock.lock();
   if (needUpdate()) {
    updateDisplayPhone(); // displayPhone在這裡被改變
   }
   lock.unlock();
  }
  return displayPhone;
 }
};

在上述程式碼中,const方法中不允許對常規成員進行變動,但mutable成員不受此限制。對Driver類來說,其固有屬性(姓名、年齡、真實手機號等)未發生改變,符合const修飾。mutable讓一些隨時可變的展示屬效能發生改變,達到了靈活程式設計的目的。

volatile

volatile用於修飾成員或變數,指示其修飾物件可能隨時變化,編譯器不要對所修飾變數進行優化(快取),每次取值應該直接讀取記憶體。由於volatile的變化來自執行期,其可以與const一起使用。兩者一起使用可能讓人費解,如果考慮場景就容易許多:CPU和GPU通過對映公用記憶體中的同一塊,GPU可能隨時往共享記憶體中寫資料。對CPU上的程式來說,const

修飾變數一直是右值,所以編譯通過。但其變數記憶體中的值在執行期間可能隨時在改變,volatile修飾是正確做法。

在多執行緒環境下,volatile可用作記憶體同步手段。例如多執行緒爆破密碼:

volatile bool found = false;

void run(string target) {
 while (!found) {
  // 計算字典口令的雜湊
  if (target == hash) {
   found = true;
   break;
  }
 }
}

volatile的修飾下,每次迴圈都會檢查記憶體中的值,達到同步的效果。

需要注意的是,volatile的值可能隨時會變,期間會導致非預期的結果。例如下面的例子求平方和:

double square(volatile double a,volatile double b) {
 return (a + b) * (a + b);
}

a和b都是隨時可變的,所以上述程式碼中的第一個a + b可能和第二個不同,導致出現非預期的結果。這種情況下,正確做法是將值賦予常規變數,然後再相乘:

double square(volatile double a,volatile double b) {
 double c = a + b;
 return c * c;
}

總結

  1. mutable只能用與類變數,不能與const同時使用;在const修飾的方法中,mutable變數數值可以發生改變;
  2. volatile只是執行期變數的值隨時可能改變,這種改變即可能來自其他執行緒,也可能來自外部系統。

以上就是聊聊C++的mutable和volatile的詳細內容,更多關於C++ mutable和volatile的資料請關注我們其它相關文章!