volatile and mutable and extern

来源:互联网 发布:python range函数菜鸟 编辑:程序博客网 时间:2024/05/21 08:47


1.volatible usage

参考地址:

http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777432.html


volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问

 有些变量是用volatile关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下: 

  volatile  BOOL  bStop   FALSE;  
   (1) 在一个线程中:  
  while(  !bStop  )   ...   
  bStop   FALSE;  
  return;    
   (2) 在另外一个线程中,要终止上面的线程循环:  
  bStop   TRUE;  
  while(  bStop  );  //等待上面的线程终止,如果bStop不使用volatile申明,那么这个循环将是一个死循环,因为bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了
    这个关键字是用来设定某个对象的存储位置在内存中,而不是寄存器中。因为一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的执行速度,例如下段代码中:  
  ...  
  int  nMyCounter   0;  
  for(;  nMyCounter<100;nMyCounter++)  
  {  
  ...  
  }  
  ...  
   在此段代码中,nMyCounter的拷贝可能存放到某个寄存器中(循环中,对nMyCounter的测试及操作总是对此寄存器中的值进行),但是另外又有段代码执行了这样的操作:nMyCounter  -=  1;这个操作中,对nMyCounter的改变是对内存中的nMyCounter进行操作,于是出现了这样一个现象:nMyCounter的改变不同步。


2.mutbale



参考地址:

http://blog.csdn.net/wuliming_sc/article/details/3717017


mutable关键字

mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量(mutable只能由于修饰类的非静态数据成员),将永远处于可变的状态,即使在一个const函数中

例1:

我们知道,假如类的成员函数不会改变对象的状态,那么这个成员函数一般会声明为const。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰。下面是一个小例子:

class ClxTest

{

public:

void Output() const;

};

 

void ClxTest::Output() const

{

cout << "Output for test!" << endl;

}

 

void OutputTest(const ClxTest& lx)

{

lx.Output();

}

ClxTest的成员函数Output是用来输出的,不会修改类的状态,所以被声明为const

函数OutputTest也是用来输出的,里面调用了对象lxOutput输出方法,为了防止在函数中调用成员函数修改任何成员变量,所以参数也被const修饰。

假如现在,我们要增添一个功能:计算每个对象的输出次数。假如用来计数的变量是普通的变量的话,那么在const成员函数Output里面是不能修改该变量的值的;而该变量跟对象的状态无关,所以应该为了修改该变量而去掉Outputconst属性。这个时候,就该我们的mutable出场了,只要用mutalbe来修饰这个变量,所有问题就迎刃而解了。下面是修改过的代码:

class ClxTest

{

public:

ClxTest();

~ClxTest();

 

void Output() const;

int GetOutputTimes() const;

 

private:

mutable int m_iTimes;

};

 

ClxTest::ClxTest()

{

m_iTimes = 0;

}

 

ClxTest::~ClxTest()

{}

 

void ClxTest::Output() const

{

cout << "Output for test!" << endl;

m_iTimes++;

}

 

int ClxTest::GetOutputTimes() const

{

return m_iTimes;

}

 

void OutputTest(const ClxTest& lx)

{

cout << lx.GetOutputTimes() << endl;

lx.Output();

cout << lx.GetOutputTimes() << endl;

}

计数器m_iTimesmutable修饰,那么它就可以突破const的限制,在被const修饰的函数里面也能被修改。

 

例2:

即使结构(或类)变量为const,其某个成员变量也可以被修改。

请看下面的代码:

struct data

{

   char name[30];

  mutable int access;

};


cosnt data veep = {"name1",1};

strcpy(veep.name,"joye jous");// not allowed

veep.access = 3; //allowed


veep的const限定符禁止程序修改veep的成员,但access成员的mutable说明符使得access不受这种限制。


3.extern关键字

参考地址:

http://blog.csdn.net/jiqiren007/article/details/5933599

http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html


extern有两个作用。
(1)当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名。
  这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,而extern "C"就是其中的一个策略。

这个功能主要用在下面的情况:

1、C++代码调用C语言代码
2、在C++的头文件中使用
3、在多个人协同开发时,可能有的人比较擅长C语言,而有的人擅长C++,这样的情况下也会有用到

(2)当extern不与"C"在一起修饰变量或函数时,如在头文件中: extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块活其他模块中使用,记住它是一个声明不是定义。

1 0
原创粉丝点击