加气站类型的网站建设,ui设计的就业前景,成都企业注册信息查询,网站开发英文合同本文转载自http://blog.csdn.net/tht2009/article/details/6920511 (1)mutable 在C中#xff0c;mutable是为了突破const的限制而设置的。被mutable修饰的变量#xff0c;将永远处于可变的状态#xff0c;即使在一个const函数中#xff0c;甚至结构体变量或者类对象为const…本文转载自http://blog.csdn.net/tht2009/article/details/6920511 (1)mutable 在C中mutable是为了突破const的限制而设置的。被mutable修饰的变量将永远处于可变的状态即使在一个const函数中甚至结构体变量或者类对象为const其mutable成员也可以被修改。 struct ST{int a;mutable int b;};const ST st{1,2};st.a11;//编译错误st.b22;//允许mutable在类中只能够修饰非静态数据成员。mutable 数据成员的使用看上去像是骗术因为它能够使const函数修改对象的数据成员。然而明智地使用 mutable 关键字可以提高代码质量因为它能够让你向用户隐藏实现细节而无须使用不确定的东西。我们知道如果类的成员函数不会改变对象的状态那么这个成员函数一般会声明成const的。但是有些时候我们需要在const的函数里面修改一些跟类状态无关的数据成员那么这个数据成员就应该被mutalbe来修饰。 class ST{int a;mutable int showCount;void Show()const;…};ST::Show(){…//显示代码a1;//错误不能在const成员函数中修改普通变量showCount;//正确}const承诺的是一旦某个变量被其修饰那么只要不使用强制转换(const_cast)在任何情况下该变量的值都不会被改变无论有意还是无意而被const修饰的函数也一样一旦某个函数被const修饰那么它便不能直接或间接改变任何函数体以外的变量的值即使是调用一个可能造成这种改变的函数都不行。这种承诺在语法上也作出严格的保证任何可能违反这种承诺的行为都会被编译器检查出来。 mutable的承诺是如果某个变量被其修饰那么这个变量将永远处于可变的状态即使在一个const函数中。这与const形成了一个对称的定义一个永远不变而另外一个是永远可变。 看一个变量或函数是否应该是const只需看它是否应该是constant或invariant而看一个变量是否应该是mutable,也只需看它是否是forever mutative。 这里出现了令人纠结的3个问题 1、为什么要保护类的成员变量不被修改 2、为什么用const保护了成员变量还要再定义一个mutable关键字来突破const的封锁线 3、到底有没有必要使用const 和 mutable这两个关键字 保护类的成员变量不在成员函数中被修改是为了保证模型的逻辑正确通过用const关键字来避免在函数中错误的修改了类对象的状态。并且在所有使用该成员函数的地方都可以更准确的预测到使用该成员函数的带来的影响。而mutable则是为了能突破const的封锁线让类的一些次要的或者是辅助性的成员变量随时可以被更改。没有使用const和mutable关键字当然没有错const和mutable关键字只是给了建模工具更多的设计约束和设计灵活性而且程序员也可以把更多的逻辑检查问题交给编译器和建模工具去做从而减轻程序员的负担。 2volatile 象const一样volatile是一个类型修饰符。volatile修饰的数据,编译器不可对其进行执行期寄存于寄存器的优化。这种特性,是为了满足多线程同步、中断、硬件编程等特殊需要。遇到这个关键字声明的变量编译器对访问该变量的代码就不再进行优化从而可以提供对特殊地址的直接访问。 volatile原意是“易变的”但这种解释简直有点误导人应该解释为“直接存取原始内存地址”比较合适。“易变”是相对与普通变量而言其值存在编译器(优化功能)未知的改变情况(即不是通过执行代码赋值改变其值的情况)而是因外在因素引起的如多线程中断等。编译器进行优化时它有时会取一些值的时候直接从寄存器里进行存取而不是从内存中获取这种优化在单线程的程序中没有问题但到了多线程程序中由于多个线程是并发运行的就有可能一个线程把某个公共的变量已经改变了这时其余线程中寄存器的值已经过时但这个线程本身还不知道以为没有改变仍从寄存器里获取就导致程序运行会出现未定义的行为。并不是因为用volatile修饰了的变量就是“易变”了假如没有外因即使用volatile定义它也不会变化。而加了volatile修饰的变量编译器将不对其相关代码执行优化而是生成对应代码直接存取原始内存地址。 一般说来volatile用在如下的几个地方 1、中断服务程序中修改的供其它程序检测的变量需要加volatile 2、多任务环境下各任务间共享的标志应该加volatile 3、存储器映射的硬件寄存器通常也要加volatile说明因为每次对它的读写都可能有不同意义 使用该关键字的例子如下 volatile int i10;int a i;...//其他代码并未明确告诉编译器对i进行过操作int b i;volatile 指出 i是随时可能发生变化的每次使用它的时候必须从i的地址中读取因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作它会自动把上次读的数据(即10)放在b中而不是重新从i里面读。这样以来如果i是一个寄存器变量或者表示一个端口数据就容易出错所以说volatile可以保证对特殊地址的直接访问。 //addr为volatile变量
addr0x57;
addr0x58;如果上述两条语句是对外部硬件执行不同的操作,那么编译器就不能像对待普通的程序那样对上述语句进行优化只认为“addr0x58;”而忽略第一条语句(即只产生一条机器代码),此时编译器会逐一的进行编译并产生相应的机器代码(两条)。 volatile总是与优化有关编译器有一种技术叫做数据流分析分析程序中的变量在哪里赋值、在哪里使用、在哪里失效分析结果可以用于常量合并常量传播等优化进一步可以死代码消除。但有时这些优化不是程序所需要的这时可以用volatile关键字禁止做这些优化它有下面的作用 1、不会在两个操作之间把volatile变量缓存在寄存器中。在多任务、中断等环境下变量可能被其他的程序改变编译器自己无法知道volatile就是告诉编译器这种情况。 2、不做常量合并、常量传播等优化所以像下面的代码if的条件不会当作无条件真。 volatile int i 1; if (i 0)... 3、对volatile变量的读写不会被优化掉。如果你对一个变量赋值但后面没用到编译器常常可以省略那个赋值操作然而对Memory Mapped IO的处理是不能这样优化的。