溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++中const、volatile、mutable怎么用

發(fā)布時(shí)間:2021-06-15 15:44:38 來(lái)源:億速云 閱讀:134 作者:小新 欄目:編程語(yǔ)言

這篇文章主要介紹了C++中const、volatile、mutable怎么用,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

const的基本使用

const的用法我覺(jué)得對(duì)于一個(gè)以后想著做一個(gè)優(yōu)秀的程序員來(lái)說(shuō),這是必須熟練掌握的技能。因?yàn)榫W(wǎng)上有好多的文章介紹它的寫(xiě)的非常好,有的我就直接拿過(guò)來(lái)了~,現(xiàn)在我們來(lái)看看他的用法。

const 要求他所修飾的對(duì)象為常量,不可被改變,不可被賦值,不可作為左值.

1、函數(shù)體內(nèi)修飾局部變量

例:

void func(){
const int a=0;
}

const作為一個(gè)類型限定詞,和int有相同的地位。

const int a; int const a;

是等價(jià)的。于是此處我們一定要清晰的明白,const修飾的對(duì)象是誰(shuí),是a還是int
const要求他所修飾的對(duì)象為常量,不可被改變,不可被賦值,不可作為左值(l-value)。所以很明顯它修飾的是a。這是一個(gè)很常見(jiàn)的使用方式:

const double pi=3.14;

在程序的后面如果企圖對(duì)pi再次賦值或者修改就會(huì)出錯(cuò)。然后看一個(gè)稍微復(fù)雜的例子。

const int* p;

因?yàn)閕nt* p;和 int *p;是等價(jià)的。
所以const int (*p)和int const (*p)是等價(jià)的?,F(xiàn)在一目了然const 修飾的是誰(shuí)? 是*p.所以p+=1;是合法的

*p+=1;是非法的因?yàn)閏onst修飾了你。

int* const p;那這個(gè)什么意思?

看const修飾的是什么? 它修飾的p。但是p是一個(gè)int型的指針,所以這個(gè)指針的地址沒(méi)有辦法修改。

p+=1; //這就是非法的
*p+=1; //這個(gè)是合法的

再看一個(gè)更復(fù)雜的例子,它是上面二者的綜合

const int* const p;說(shuō)明p自己是常量,且p指向的變量也是常量。
于是

p+=1; //非法
*p+=1; //非法

const 還有一個(gè)作用就是用于修飾常量靜態(tài)字符串。例如:

const char* name=David;

如果沒(méi)有const,我們可能會(huì)在后面有意無(wú)意的寫(xiě)name[4]='x'這樣的語(yǔ)句,這樣會(huì)導(dǎo)致對(duì)只讀內(nèi)存區(qū)域的賦值,然后程序會(huì)立刻異常終止。有了 const,這個(gè)錯(cuò)誤就能在程序被編譯的時(shí)候就立即檢查出來(lái),這就是const的好處。讓邏輯錯(cuò)誤在編譯期被發(fā)現(xiàn)。

2、在函數(shù)聲明時(shí)修飾參數(shù)
舉個(gè)例子void * myMemMove(void *dst,constvoid *src,intcount )這是我寫(xiě)的memmove函數(shù)的聲明,這個(gè)函數(shù)的意思就是(任意類型)把*src的內(nèi)容復(fù)制給*dst,我們現(xiàn)在很明顯的看到*src它只讓你復(fù)制,你不能修改它的值,所以怕你在以后的函數(shù)的定義里出現(xiàn)問(wèn)題現(xiàn)在在聲明里限制你。

3、全局變量
我們的原則依然是,盡可能少的使用全局變量。我們的第二條規(guī)則 則是,盡可能多的使用const。如果一個(gè)全局變量只在本文件中使用,那么用法和前面所說(shuō)的函數(shù)局部變量沒(méi)有什么區(qū)別。如果它要在多個(gè)文件間共享,那么就牽扯到一個(gè)存儲(chǔ)類型的問(wèn)題。

有兩種方式。

1.使用extern
例如
/* test.h */
extern const double pi;
/* test.c */
const double pi=3.14;

然后其他需要使用pi這個(gè)變量的,包含test.h

#include test.h

或者,自己把那句聲明復(fù)制一遍就好。

這樣做的結(jié)果是,整個(gè)程序鏈接完后,所有需要使用pi這個(gè)變量的共享一個(gè)存儲(chǔ)區(qū)域。

2.使用static,靜態(tài)外部存儲(chǔ)類

/* constant.h */
static const pi=3.14;

需要使用這個(gè)變量的*.c文件中,必須包含這個(gè)頭文件。

前面的static一定不能少。否則鏈接的時(shí)候會(huì)報(bào)告說(shuō)該變量被多次定義。這樣做的結(jié)果是,每個(gè)包含了constant.h的*.c文件,都有一份該變量自己的copy,該變量實(shí)際上還是被定義了多次,占用了多個(gè)存儲(chǔ)空間,不過(guò)在加了static關(guān)鍵字后,解決了文件間重定義的沖突。壞處是浪費(fèi)了存儲(chǔ)空間,導(dǎo)致鏈接完后的可執(zhí)行文件變大。但是通常,這個(gè),小小幾字節(jié)的變化,不是問(wèn)題。好處是,你不用關(guān)心這個(gè)變量是在哪個(gè)文件中被初始化的。
其實(shí)const我覺(jué)得更多是程序員自己限制自己,自己告訴自己后面哪里不能出現(xiàn)錯(cuò)誤

舉個(gè)例子吧。

#include<stdio.h>
#include<Windows.h>
int main()
{
	int *p;
	const int a = 0;
	p = &a;
	*p = 3;
	printf("a= %d \n", a);
	system("pause");
	return 0;
}

現(xiàn)在看看運(yùn)行結(jié)果

C++中const、volatile、mutable怎么用

現(xiàn)在我要說(shuō)一個(gè)const操作里面比較騷的一些做法,

舉個(gè)例子我們以前寫(xiě)過(guò)的一個(gè)類,我們會(huì)使用operator[]來(lái)返回一個(gè)reference的指向,這個(gè)一般情況我們都會(huì)寫(xiě)一個(gè)

const的也會(huì)寫(xiě)一個(gè)非const的opeartor[].這是我們最常見(jiàn)的一個(gè)代碼:

T& operator[](int position) 
{ 
 return xxx[position]; 
} 
const T& operator[](int position) const 
{ 
 return xxx[position]; 
}

這是我們平時(shí)寫(xiě)的初級(jí)的代碼,但是現(xiàn)在當(dāng)我們要寫(xiě)一個(gè)TextBlock內(nèi)的opeartor[]不單只返回一個(gè)referencr了,也可能執(zhí)行邊界檢查,日志訪問(wèn)信息,還有什么數(shù)據(jù)完善性檢驗(yàn)等等一大堆繁瑣的代碼,這個(gè)時(shí)候當(dāng)你實(shí)現(xiàn)operator[] const和operator[]() const,的時(shí)候兩份代碼大部分都一樣,這里伴隨的是代碼重復(fù),編譯時(shí)間變長(zhǎng),維護(hù)代碼膨脹等等頭疼的問(wèn)題. 當(dāng)然啦,你可以讓上述那些繁瑣的函數(shù)全部封裝的別的函數(shù)中,然后分別在operator[]()和operator[]()const當(dāng)中調(diào)用但是你還說(shuō)重復(fù)了一些代碼比如兩次return語(yǔ)句,函數(shù)調(diào)用.真正該做的是實(shí)現(xiàn)operator[]的機(jī)能一次并使用它兩次。也就是你只需要寫(xiě)一個(gè)函數(shù),令另外一個(gè)調(diào)用這個(gè),這促使我們將常量性轉(zhuǎn)移. 接下來(lái) 見(jiàn)證奇跡我們來(lái)看看下面這個(gè)代碼是怎么實(shí)現(xiàn)的上述的操作的:

class TextBlock 
{ 
public: 
 ... 
 const char& operator[](std::size_t position) const 
 { 
  ... 
  ... 
  ... 
  return text[position]; 
 } 
 
 char& operator[](std::size_t position) 
 { 
  return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]); 
 } 
};

來(lái)仔細(xì)看這個(gè)操作;return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
首先把*this強(qiáng)制轉(zhuǎn)換為const TextBlock,再然后調(diào)用const的operator[],最后再把const的operator[]的返回值的const常量性取消,然后返回一個(gè)非const的值. 這里的調(diào)用實(shí)在是太妙了,我們可以思考一下,好好想想這里的深意.
但是會(huì)有人說(shuō),為什么不用const operator[]調(diào)用operator[]呢,這樣強(qiáng)制兩個(gè)都可以行的通啊.這樣想是錯(cuò)的!

令const版本調(diào)用調(diào)用no-const版本以避免重復(fù)并不是你該做的事情. 記住const所修飾函數(shù)的承諾就是我絕對(duì)不會(huì)修改你,no-const函數(shù)可沒(méi)有這種承諾,所以你讓一個(gè)const函數(shù)去調(diào)用一個(gè)no-const函數(shù)是不現(xiàn)實(shí)的. over其實(shí)const有很多可以玩的屬性,只要我們想到就可以去實(shí)現(xiàn),這里就說(shuō)這么一個(gè)就ok. 接下來(lái)我們來(lái)瞧瞧另外兩個(gè)關(guān)鍵字.

C++中的mutable關(guān)鍵字

mutalbe的中文意思是“可變的,易變的”,跟constant(既C++中的const)是反義詞。

在C++中,mutable也是為了突破const的限制而設(shè)置的。被mutable修飾的變量,將永遠(yuǎn)處于可變的狀態(tài),即使在一個(gè)const函數(shù)中。

我們知道,被const關(guān)鍵字修飾的函數(shù)的一個(gè)重要作用就是為了能夠保護(hù)類中的成員變量。即:該函數(shù)可以使用類中的所有成員變量,但是不能修改他們的值。然而,在某些特殊情況下,我們還是需要在const函數(shù)中修改類的某些成員變量,因?yàn)橐薷牡某蓡T變量與類本身并無(wú)多少關(guān)系,即使修改了也不會(huì)對(duì)類造成多少影響。當(dāng)然,你可以說(shuō),你可以去掉該函數(shù)的const關(guān)鍵字呀!但問(wèn)題是,我只想修改某個(gè)成員變量,其余成員變量仍然希望被const保護(hù)。

經(jīng)典的應(yīng)用場(chǎng)景比如說(shuō):我要測(cè)試一個(gè)方法的被調(diào)用次數(shù)。

class Person {
public:
 Person();
 ~Person();

 int getAge() const; /*調(diào)用方法*/
 int getCallingTimes() const; /*獲取上面的getAge()方法被調(diào)用了多少次*/
private:
 int age;
 char *name;
 float score;
 int m_nums;   /*用于統(tǒng)計(jì)次數(shù)*/
};

最普遍的作法就是在getAge()的方法體內(nèi)對(duì)m_nums這個(gè)變量進(jìn)行加+1,但是getAge()方法又是const方法,無(wú)法修改m_nums這個(gè)變量,我又不想去掉const關(guān)鍵字讓別人能夠修改age等成員變量,這個(gè)時(shí)候mutable關(guān)鍵字就派上用場(chǎng)了:

#include <iostream>

class Person {
public:
 Person();
 ~Person();

 int getAge() const; /*調(diào)用方法*/
 int getCallingTimes() const; /*獲取上面的getAge()方法被調(diào)用了多少次*/
private:
 int age;
 char *name;
 float score;
 mutable int m_nums;   /*用于統(tǒng)計(jì)次數(shù)*/
};

Person::Person()
{
 m_nums = 0;
}

Person::~Person(){}

int Person::getAge() const
{
 std::cout << "Calling the method" << std::endl;
 m_nums++;
 // age = 4; 仍然無(wú)法修改該成員變量
 return age;
}

int Person::getCallingTimes()const
{
 return m_nums;
}

int main()
{
 Person *person = new Person();
 for (int i = 0; i < 10; i++) {
  person->getAge();
 }
 std::cout << "getAge()方法被調(diào)用了" << person->getCallingTimes() << "次" << std::endl;
 delete person;

 getchar();
 return 0;
}

運(yùn)行結(jié)果:

Calling the method
Calling the method
Calling the method
Calling the method
Calling the method
Calling the method
Calling the method
Calling the method
Calling the method
Calling the method

getAge()方法被調(diào)用了10次

這樣我們既保護(hù)了別的成員變量,又能夠使計(jì)數(shù)器的值進(jìn)行累加。

需要注意的是:mutable不能修飾const 和 static 類型的變量。

接著補(bǔ)充

實(shí)際運(yùn)用起來(lái)也非常容易,就是你想改變的元素被const修飾了,你就往它前面加上mutable那么你就無(wú)敵了..

我就舉一個(gè)最簡(jiǎn)單的例子,我定一個(gè)AA類,我在AA類中定義一個(gè)MT()函數(shù),該函數(shù)屬性為const屬性,再然后我

想在MT()函數(shù)中添加該函數(shù)執(zhí)行多少次時(shí),程序編不過(guò)去了. 因?yàn)閏onst修飾的函數(shù)里面的所有值都不能修改.

class AA
{
public:
	void MT() const
	{
		i++;
		cout << "hehe";
		cout << "執(zhí)行了" << i << "次該程序";
	}
 
private:
	int i = 0;
};

但是這樣編不過(guò)去啊,因?yàn)镸T()函數(shù)為const函數(shù),所以不能修改i的值,但是如果我在這里使用mutable關(guān)鍵字的

話,現(xiàn)在我們把i加上mutable關(guān)鍵字,這樣它永遠(yuǎn)就是一個(gè)可變的了. 來(lái)我們加上去試一試,

class AA
{
public:
	void MT() const
	{
		i++;
		cout << "hehe" << " ";
		cout << "執(zhí)行了" << i << "次該程序" << endl;;
	}
 
private:
	mutable int i = 0;
};
 
int main()
{
	AA a;
	a.MT();
	a.MT();
	a.MT();
	a.MT();
	return 0;
}

運(yùn)行結(jié)果:

C++中const、volatile、mutable怎么用

這就是mutable的最簡(jiǎn)單的一個(gè)應(yīng)用,以后可以根據(jù)需求來(lái)使用~

volatile

為什么使用volatile ?
C/C++中的 volatile 關(guān)鍵字 和const對(duì)應(yīng),用來(lái)修飾變量,通常用于建立語(yǔ)言級(jí)別的memory barrier。這是BS在“The C++ Programming Language”對(duì)volatile修飾詞的解釋:
A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.

volatile 關(guān)鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(tǒng),硬件或者其他線程等。

遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對(duì)訪問(wèn)該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對(duì)特殊地址的穩(wěn)定訪問(wèn)。聲明時(shí)語(yǔ)法:int volatile vInt; 當(dāng)要求使用 volatile 聲明的變量的值的時(shí)候,系統(tǒng)總是重新從它所在的內(nèi)存讀取數(shù)據(jù),即使它前面的指令剛剛從該處讀取過(guò)數(shù)據(jù)。而且讀取的數(shù)據(jù)立刻被保存。例如:

volatile int i=10; 
int a = i; 
... 
// 其他代碼,并未明確告訴編譯器,對(duì) i 進(jìn)行過(guò)操作 
int b = i; 
volatile int i=10;
int a = i;
...
// 其他代碼,并未明確告訴編譯器,對(duì) i 進(jìn)行過(guò)操作
int b = i;

volatile 指出 i 是隨時(shí)可能發(fā)生變化的,每次使用它的時(shí)候必須從 i的地址中讀取,因而編譯器生成的匯編代碼會(huì)重新從i的地址讀取數(shù)據(jù)放在 b 中。而優(yōu)化做法是,由于編譯器發(fā)現(xiàn)兩次從 i讀數(shù)據(jù)的代碼之間的代碼沒(méi)有對(duì) i 進(jìn)行過(guò)操作,它會(huì)自動(dòng)把上次讀的數(shù)據(jù)放在 b 中。而不是重新從 i 里面讀。這樣以來(lái),如果 i是一個(gè)寄存器變量或者表示一個(gè)端口數(shù)據(jù)就容易出錯(cuò),所以說(shuō) volatile 可以保證對(duì)特殊地址的穩(wěn)定訪問(wèn)。注意,在 VC 6 中,一般調(diào)試模式?jīng)]有進(jìn)行代碼優(yōu)化,所以這個(gè)關(guān)鍵字的作用看不出來(lái)。下面通過(guò)插入?yún)R編代碼,測(cè)試有無(wú) volatile 關(guān)鍵字,對(duì)程序最終代碼的影響:

輸入下面的代碼:

#include <stdio.h> 
  
void main() 
{ 
  int i = 10; 
  int a = i; 
   
  printf("i = %d", a); 
 
  // 下面匯編語(yǔ)句的作用就是改變內(nèi)存中 i 的值 
  // 但是又不讓編譯器知道 
  __asm{ 
    mov dword ptr [ebp-4], 20h 
  } 
    
  int b = i; 
  printf("i = %d", b); 
} 
#include <stdio.h>
 
void main()
{
  int i = 10;
  int a = i;
  
  printf("i = %d", a);
 
  // 下面匯編語(yǔ)句的作用就是改變內(nèi)存中 i 的值
  // 但是又不讓編譯器知道
  __asm{
    mov dword ptr [ebp-4], 20h
  }
   
  int b = i;
  printf("i = %d", b);
}

然后,在 Debug 版本模式運(yùn)行程序,輸出結(jié)果如下:

i = 10
i = 32
然后,在 Release 版本模式運(yùn)行程序,輸出結(jié)果如下:

i = 10
i = 10
輸出的結(jié)果明顯表明,Release 模式下,編譯器對(duì)代碼進(jìn)行了優(yōu)化,第二次沒(méi)有輸出正確的 i 值。下面,我們把 i 的聲明加上 volatile 關(guān)鍵字,看看有什么變化:

#include <stdio.h> 
 void main() 
{ 
  volatile int i = 10; 
  int a = i; 
  printf("i = %d", a); 
  __asm { 
    mov dword ptr [ebp-4], 20h 
  } 
   
  int b = i; 
  printf("i = %d", b); 
} 
#include <stdio.h>
 
void main()
{
  volatile int i = 10;
  int a = i;
 
  printf("i = %d", a);
  __asm {
    mov dword ptr [ebp-4], 20h
  }
  
  int b = i;
  printf("i = %d", b);
}

分別在 Debug 和 Release 版本運(yùn)行程序,輸出都是:

i = 10
i = 32

這說(shuō)明這個(gè) volatile 關(guān)鍵字發(fā)揮了它的作用。其實(shí)不只是“內(nèi)嵌匯編操縱?!边@種方式屬于編譯無(wú)法識(shí)別的變量改變,另外更多的可能是多線程并發(fā)訪問(wèn)共享變量時(shí),一個(gè)線程改變了變量的值,怎樣讓改變后的值對(duì)其它線程 visible。一般說(shuō)來(lái),volatile用在如下的幾個(gè)地方:
1) 中斷服務(wù)程序中修改的供其它程序檢測(cè)的變量需要加volatile;
2) 多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile;
3) 存儲(chǔ)器映射的硬件寄存器通常也要加volatile說(shuō)明,因?yàn)槊看螌?duì)它的讀寫(xiě)都可能由不同意義;

2.volatile 指針

和 const 修飾詞類似,const 有常量指針和指針常量的說(shuō)法,volatile 也有相應(yīng)的概念:

修飾由指針指向的對(duì)象、數(shù)據(jù)是 const 或 volatile 的:

const char* cpch; 
volatile char* vpch; 
const char* cpch;
volatile char* vpch;

注意:對(duì)于 VC,這個(gè)特性實(shí)現(xiàn)在 VC 8 之后才是安全的。指針自身的值——一個(gè)代表地址的整數(shù)變量,是 const 或 volatile 的:

char*const pchc; 
char*volatile pchv; 
char*const pchc;
char*volatile pchv;

注意:

(1) 可以把一個(gè)非volatile int賦給volatile int,但是不能把非volatile對(duì)象賦給一個(gè)volatile對(duì)象。

(2) 除了基本類型外,對(duì)用戶定義類型也可以用volatile類型進(jìn)行修飾。
(3) C++中一個(gè)有volatile標(biāo)識(shí)符的類只能訪問(wèn)它接口的子集,一個(gè)由類的實(shí)現(xiàn)者控制的子集。用戶只能用const_cast來(lái)獲得對(duì)類型接口的完全訪問(wèn)。此外,volatile向const一樣會(huì)從類傳遞到它的成員。

3. 多線程下的volatile
有些變量是用volatile關(guān)鍵字聲明的。當(dāng)兩個(gè)線程都要用到某一個(gè)變量且該變量的值會(huì)被改變時(shí),應(yīng)該用volatile聲明,該關(guān)鍵字的作用是防止優(yōu)化編譯器把變量從內(nèi)存裝入CPU寄存器中。如果變量被裝入寄存器,那么兩個(gè)線程有可能一個(gè)使用內(nèi)存中的變量,一個(gè)使用寄存器中的變量,這會(huì)造成程序的錯(cuò)誤執(zhí)行。volatile的意思是讓編譯器每次操作該變量時(shí)一定要從內(nèi)存中真正取出,而不是使用已經(jīng)存在寄存器中的值,如下:

volatile BOOL bStop = FALSE; 
// 在一個(gè)線程中:  
 while( !bStop ) { ... }  
bStop = FALSE;  
return;   
 
//在另外一個(gè)線程中,要終止上面的線程循環(huán):  
bStop = TRUE;  
while( bStop ); //等待上面的線程終止, 
volatile BOOL bStop = FALSE; 
 
// 在一個(gè)線程中: 
 while( !bStop ) { ... } 
bStop = FALSE; 
return;  
 
//在另外一個(gè)線程中,要終止上面的線程循環(huán): 
bStop = TRUE; 
while( bStop ); //等待上面的線程終止,

如果bStop不使用volatile申明,那么這個(gè)循環(huán)將是一個(gè)死循環(huán),因?yàn)閎Stop已經(jīng)讀取到了寄存器中,寄存器中bStop的值永遠(yuǎn)不會(huì)變成FALSE,加上volatile,程序在執(zhí)行時(shí),每次均從內(nèi)存中讀出bStop的值,就不會(huì)死循環(huán)了。
這個(gè)關(guān)鍵字是用來(lái)設(shè)定某個(gè)對(duì)象的存儲(chǔ)位置在內(nèi)存中,而不是寄存器中。因?yàn)橐话愕膶?duì)象編譯器可能會(huì)將其的拷貝放在寄存器中用以加快指令的執(zhí)行速度,例如下段代碼中:

在此段代碼中,nMyCounter的拷貝可能存放到某個(gè)寄存器中(循環(huán)中,對(duì)nMyCounter的測(cè)試及操作總是對(duì)此寄存器中的值進(jìn)行),但是另外又有段代碼執(zhí)行了這樣的操作:nMyCounter -= 1;這個(gè)操作中,對(duì)nMyCounter的改變是對(duì)內(nèi)存中的nMyCounter進(jìn)行操作,于是出現(xiàn)了這樣一個(gè)現(xiàn)象:nMyCounter的改變不同步。

下面是volatile變量的幾個(gè)例子:

1.并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器

2.一個(gè)中斷服務(wù)子程序中會(huì)訪問(wèn)到的非自動(dòng)變量(Non-automatic variables)

3.多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量

看下面例題:

int square(volatile int *ptr)
{
  return *ptr * *ptr;
}

這個(gè)程序有什么問(wèn)題嗎? 如果我們不去關(guān)心volatile關(guān)鍵字的話,那么這個(gè)程序你怎么看都會(huì)覺(jué)得沒(méi)多大問(wèn)題.但是這里

面問(wèn)題大這ne, 首先參數(shù)聲明為volatile就是表明*ptr可能會(huì)隨時(shí)改變.上述代碼運(yùn)行時(shí),編譯器可能產(chǎn)生這樣的代碼:

int square(volatile int *ptr)
{
  int a,b;
  a = *ptr;
  b = *ptr;
  return a * b;
}

因?yàn)槟愕?ptr是隨時(shí)都可以意想不到的變化,所以有可能a*b的時(shí)候,a b的值不相同. 這樣你就得到一個(gè)錯(cuò)誤的結(jié)果

改正后的程序:

int square(volatile int *ptr)
{
  int a;
  a = *ptr;
  return a * a;
}

第二個(gè)問(wèn)題,看如下代碼:

#include<iostream> 
#include<Windows.h> 
#include<assert.h> 
 
using namespace std; 
 
int main() 
{ 
  const int a = 2; 
  int *p = const_cast<int*>(&a); 
  *p = 3; 
  cout << a << endl; 
  system("pause"); 
  return 0; 
}

我們有理由的認(rèn)為在內(nèi)存當(dāng)中a的值被修改為3,但是結(jié)果呢? 我們來(lái)看一看

C++中const、volatile、mutable怎么用

這不科學(xué)???? 我們?cè)俅蜷_(kāi)監(jiān)視窗口看一下a的值.

C++中const、volatile、mutable怎么用

我們都知道監(jiān)視窗口看到的都是從內(nèi)存當(dāng)中拿到的,但是為什么內(nèi)存當(dāng)中為3,打印出來(lái)就是2呢? 我來(lái)解釋一下.

C++編譯器具有優(yōu)化功能,當(dāng)你定一個(gè)const的常量的時(shí)候,系統(tǒng)覺(jué)得它不會(huì)被改變了,于是做一個(gè)優(yōu)化把該常量存到寄

存器當(dāng)中,下次訪問(wèn)的過(guò)程更快速一點(diǎn). 所以當(dāng)顯示窗口讀取數(shù)據(jù)的時(shí)候,他會(huì)直接去寄存器當(dāng)中讀取數(shù)據(jù).而不是去

內(nèi)存,所以導(dǎo)致我們明明該掉了a的值,卻打印不出來(lái).

這個(gè)時(shí)候該我們的volatile出馬了,往i前面加一個(gè)volatile之后就會(huì)解決這個(gè)問(wèn)題,來(lái)看結(jié)果:

C++中const、volatile、mutable怎么用

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“C++中const、volatile、mutable怎么用”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI