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:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
#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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/fengbingchun/article/details/104109696








发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。