C++中volatile和mutable关键字用法详解

C/C++中的volatile关键字和const对应,用来修饰变量,用于告诉编译器该变量值是不稳定的,可能被更改。使用volatile注意事项:

(1). 编译器会对带有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)。

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

(3). 中断服务程序中访问到的变量最好带上volatile。

(4). 并行设备的硬件寄存器的变量最好带上volatile。

(5). 声明的变量可以同时带有const和volatile关键字。

(6). 多个volatile变量间的操作,是不会被编译器交换顺序的,能够保证volatile变量间的顺序性,编译器不会进行乱序优化(The value cannot change in order of assignment)。但volatile变量和非volatile变量之间的顺序,编译器不保证顺序,可能会进行乱序优化。

C++中的mutable关键字使用场景

(1). 允许即使包含它的对象被声明为const时仍可修改声明为mutable的类成员(sometimes there is requirement to modify one or more data members of class/struct through const function even though you don't want the function to update other members of class/struct. This task can be easily performed by using mutable keyword)。

(2). 应用在C++11 lambda表达式来表示按值捕获的值是可修改的,默认情况下是不可修改的,但修改仅在lambda式内有效(since c++11 mutable can be used on a lambda to denote that things captured by value are modifiable (they aren't by default))。

详细用法见下面的测试代码,下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "volatile_mutable.hpp"
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <mutex>
#include <string.h>

namespace volatile_mutable_ {

///////////////////////////////////////////////////////////
int test_volatile_1()
{
 volatile int i1 = 0; // correct
 int volatile i2 = 0; // correct

 return 0;
}

///////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/c/language/volatile
int test_volatile_2()
{
{ // Any attempt to read or write to an object whose type is volatile-qualified through a non-volatile lvalue results in undefined behavior
 volatile int n = 1; // object of volatile-qualified type
 int* p = (int*)&n;
 int val = *p; // undefined behavior in C, Note: link does not report an error under C++
 fprintf(stdout, "val: %d\n", val);
}

{ // A member of a volatile-qualified structure or union type acquires the qualification of the type it belongs to
 typedef struct ss { int i; const int ci; } s;
 // the type of s.i is int, the type of s.ci is const int
 volatile s vs = { 1, 2 };
 // the types of vs.i and vs.ci are volatile int and const volatile int
}

{ // If an array type is declared with the volatile type qualifier (through the use of typedef), the array type is not volatile-qualified, but its element type is
 typedef int A[2][3];
 volatile A a = { {4, 5, 6}, {7, 8, 9} }; // array of array of volatile int
 //int* pi = a[0]; // Error: a[0] has type volatile int*
 volatile int* pi = a[0];
}

{ // A pointer to a non-volatile type can be implicitly converted to a pointer to the volatile-qualified version of the same or compatible type. The reverse conversion can be performed with a cast expression
 int* p = nullptr;
 volatile int* vp = p; // OK: adds qualifiers (int to volatile int)
 //p = vp; // Error: discards qualifiers (volatile int to int)
 p = (int*)vp; // OK: cast
}

{ // volatile disable optimizations
 clock_t t = clock();
 double d = 0.0;
 for (int n = 0; n < 10000; ++n)
 for (int m = 0; m < 10000; ++m)
  d += d * n*m; // reads and writes to a non-volatile
 fprintf(stdout, "Modified a non-volatile variable 100m times. Time used: %.2f seconds\n", (double)(clock() - t) / CLOCKS_PER_SEC);

 t = clock();
 volatile double vd = 0.0;
 for (int n = 0; n < 10000; ++n)
 for (int m = 0; m < 10000; ++m)
  vd += vd * n*m; // reads and writes to a volatile
 fprintf(stdout, "Modified a volatile variable 100m times. Time used: %.2f seconds\n", (double)(clock() - t) / CLOCKS_PER_SEC);
}

 return 0;
}

///////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/cpp/language/cv
int test_volatile_3()
{
 int n1 = 0;      // non-const object
 const int n2 = 0;   // const object
 int const n3 = 0;   // const object (same as n2)
 volatile int n4 = 0; // volatile object
 const struct {
 int n1;
 mutable int n2;
 } x = { 0, 0 };   // const object with mutable member

 n1 = 1; // ok, modifiable object
 //n2 = 2; // error: non-modifiable object
 n4 = 3; // ok, treated as a side-effect
 //x.n1 = 4; // error: member of a const object is const
 x.n2 = 4; // ok, mutable member of a const object isn't const

 const int& r1 = n1; // reference to const bound to non-const object
 //r1 = 2; // error: attempt to modify through reference to const
 const_cast<int&>(r1) = 2; // ok, modifies non-const object n1
 fprintf(stdout, "n1: %d\n", n1); // 2

 const int& r2 = n2; // reference to const bound to const object
 //r2 = 2; // error: attempt to modify through reference to const
 const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2, Note: link does not report an error under C++
 fprintf(stdout, "n2: %d\n", n2); // 0

 return 0;
}

///////////////////////////////////////////////////////////
// reference: https://www.geeksforgeeks.org/understanding-volatile-qualifier-in-c/
int test_volatile_4()
{
{
 const int local = 10;
 int *ptr = (int*)&local;
 fprintf(stdout, "Initial value of local : %d \n", local); // 10

 *ptr = 100;
 fprintf(stdout, "Modified value of local: %d \n", local); // 10
}

{
 const volatile int local = 10;
 int *ptr = (int*)&local;
 fprintf(stdout, "Initial value of local : %d \n", local); // 10

 *ptr = 100;
 fprintf(stdout, "Modified value of local: %d \n", local); // 100
}

 return 0;
}

///////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/cpp/language/cv
int test_mutable_1()
{
 // Mutable is used to specify that the member does not affect the externally visible state of the class (as often used for mutexes,
 // memo caches, lazy evaluation, and access instrumentation)
 class ThreadsafeCounter {
 public:
 int get() const {
  std::lock_guard<std::mutex> lk(m);
  return data;
 }
 void inc() {
  std::lock_guard<std::mutex> lk(m);
  ++data;
 }

 private:
 mutable std::mutex m; // The "M&M rule": mutable and mutex go together
 int data = 0;
 };

 return 0;
}

///////////////////////////////////////////////////////////
// reference: https://www.tutorialspoint.com/cplusplus-mutable-keyword
int test_mutable_2()
{
 class Test {
 public:
 Test(int x = 0, int y = 0) : a(x), b(y) {}

 void seta(int x = 0) { a = x; }
 void setb(int y = 0) { b = y; }
 void disp() { fprintf(stdout, "a: %d, b: %d\n", a, b); }

 public:
 int a;
 mutable int b;
 };

 const Test t(10, 20);
 fprintf(stdout, "t.a: %d, t.b: %d \n", t.a, t.b); // 10, 20

 //t.a=30; // Error occurs because a can not be changed, because object is constant.
 t.b = 100; // b still can be changed, because b is mutable.
 fprintf(stdout, "t.a: %d, t.b: %d \n", t.a, t.b); // 10, 100

 return 0;
}

///////////////////////////////////////////////////////////
// reference: https://www.geeksforgeeks.org/c-mutable-keyword/
int test_mutable_3()
{
 using std::cout;
 using std::endl;

 class Customer {
 public:
 Customer(char* s, char* m, int a, int p)
 {
  strcpy(name, s);
  strcpy(placedorder, m);
  tableno = a;
  bill = p;
 }

 void changePlacedOrder(char* p) const { strcpy(placedorder, p); }
 void changeBill(int s) const { bill = s; }

 void display() const
 {
  cout << "Customer name is: " << name << endl;
  cout << "Food ordered by customer is: " << placedorder << endl;
  cout << "table no is: " << tableno << endl;
  cout << "Total payable amount: " << bill << endl;
 }

 private:
 char name[25];
 mutable char placedorder[50];
 int tableno;
 mutable int bill;
 };

 const Customer c1("Pravasi Meet", "Ice Cream", 3, 100);
 c1.display();
 c1.changePlacedOrder("GulabJammuns");
 c1.changeBill(150);
 c1.display();

 return 0;
}

///////////////////////////////////////////////////////////
// reference: https://stackoverflow.com/questions/105014/does-the-mutable-keyword-have-any-purpose-other-than-allowing-the-variable-to
int test_mutable_4()
{
 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
 fprintf(stdout, "x: %d\n", x); // 0

 return 0;
}

} // namespace volatile_mutable_

GitHub:https://github.com/fengbingchun/Messy_Test

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C++中const、volatile、mutable使用方法小结

    相信const大家对他并不陌生,可能大家在日常的编写代码当中就会时常用到const,但是剩下的两个关键字不知道我们有 没有使用过volatile和mutable两个关键字其实不算特别常用,但是我们一定要知道这个关键字有什么用,应该怎么用.首 先const的基本操作我曾经写过一篇博客:const的基本使用 现在我要说一个const操作里面比较骚的一些做法, 举个例子我们以前写过的一个类,我们会使用operator[]来返回一个reference的指向,这个一般情况我们都会写一个const的也会写一

  • 浅谈C++中的mutable和volatile关键字

    1.mutable 在C++中,mutable是为了突破const的限制而设置的.被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中,甚至结构体变量或者类对象为const,其mutable成员也可以被修改.mutable在类中只能够修饰非静态数据成员. #include <iostream> using namespace std; class test { mutable int a; int b; public: test(int _a,int _b) :a(_a

  • C++中mutable与volatile的深入理解

    前言 C++中修饰数据可变的关键字有三个:const.volatile和mutable.const比较好理解,表示其修饰的内容不可改变(至少编译期不可改变),而volatile和mutable恰好相反,指示数据总是可变的.mutable和volatile均可以和const搭配使用,但两者在使用上有比较大差别. 下面话不多说了,来一起看看详细的介绍吧 mutable mutable只能作用在类成员上,指示其数据总是可变的.不能和const 同时修饰一个成员,但能配合使用:const修饰的方法中,m

  • C++中volatile和mutable关键字用法详解

    C/C++中的volatile关键字和const对应,用来修饰变量,用于告诉编译器该变量值是不稳定的,可能被更改.使用volatile注意事项: (1). 编译器会对带有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 optimiza

  • Linux中 sed 和 awk的用法详解

    sed用法: sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法 sed命令行格式为: sed [-nefri] 'command' 输入文本 常用选项: -n∶使用安静(silent)模式.在一般 sed 的用法中,所有来自 STDIN的资料一般都会被列出到萤幕上.但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来. -e∶直接在指令列模式上进行 sed 的

  • Python中 Global和Nonlocal的用法详解

    nonlocal 和 global 也很容易混淆.简单记录下自己的理解. 解释 global 总之一句话,作用域是全局的,就是会修改这个变量对应地址的值. global 语句是一个声明,它适用于整个当前代码块. 这意味着列出的标识符将被解释为全局变量. 尽管自由变量可能指的是全局变量而不被声明为全局变量. global 语句中列出的名称不得用于该全局语句之前的文本代码块中. global 语句中列出的名称不能定义为形式参数,也不能在 for 循环控制目标. class 定义.函数定义. impo

  • Java instanceof关键字用法详解及注意事项

    instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为: boolean result = obj instanceof Class 其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false. 注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,

  • Python pandas中apply函数简介以及用法详解

    目录 1.基本信息 2.语法结构 3.使用案例 3.1 DataFrame使用apply 3.2 Series使用apply 3.3 其他案例 4.总结 参考链接: 1.基本信息 ​ Pandas 的 apply() 方法是用来调用一个函数(Python method),让此函数对数据对象进行批量处理.Pandas 的很多对象都可以使用 apply() 来调用函数,如 Dataframe.Series.分组对象.各种时间序列等. 2.语法结构 ​ apply() 使用时,通常放入一个 lambd

  • JSP 中request与response的用法详解

    JSP 中request与response的用法详解 概要: 在学习这两个对象之前,我们应该已经有了http协议的基本了解了,如果不清楚http协议的可以看我的关于http协议的介绍.因为其实request和response的使用大部分都是对http协议的操作. request对象的介绍 我们先从request对象进行介绍: 我们知道http协议定义了请求服务器的格式: 请求行 请求头 空格 请求体(get请求没有请求体) 好了,这里我们就不详细介绍了,我们只看几个应用就可以了,没什么难度: 应

  • IOS开发中NSURL的基本操作及用法详解

    NSURL其实就是我们在浏览器上看到的网站地址,这不就是一个字符串么,为什么还要在写一个NSURL呢,主要是因为网站地址的字符串都比较复杂,包括很多请求参数,这样在请求过程中需要解析出来每个部门,所以封装一个NSURL,操作很方便. 1.URL URL是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址.互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它. URL可能包含远程服务器上的资源的位置,本地磁盘上的文件的路径,甚

  • JavaScript中SetInterval与setTimeout的用法详解

    setTimeout 描述 setTimeout(code,millisec) setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式. 注:调用过程中,可以使用clearTimeout(id_of_settimeout)终止 参数 描述 code 必需,要调用的函数后要执行的 JavaScript 代码串. millisec 必需,在执行代码前需等待的毫秒数. setTimeinterval setInterval(code,millisec[,"lang"]) 参数

  • C++中auto_ptr智能指针的用法详解

    智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限.本文总结的8个问题足以涵盖auto_ptr的大部分内容. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有

  • Python中index()和seek()的用法(详解)

    1.index() 一般用处是在序列中检索参数并返回第一次出现的索引,没找到就会报错,比如: >>> t=tuple('Allen') >>> t ('A', 'l', 'l', 'e', 'n') >>> t.index('a') Traceback (most recent call last): File "<pyshell#2>", line 1, in <module> t.index('a') V

随机推荐