const 和 mutable在C++存在已经很多年了,对于如今的这两个关键字你了解多少?

Problem

JG Question

1. 什么是“共享变量”?

Guru Question

2. const 和 mutable对于共享变量来说意味着什么?

3. 在C++98和C++11两者间,const 和 mutable有什么区别?

Stop and thinking……

Solution

1. 什么是“共享变量”?

共享变量是在同一时间可以被多个线程同时访问的变量。

这个概念在C++内存模型中很重要。例如:C++内存模型禁止创造一个写入“潜在共享变量区”,这不会被写入到程序执行的顺序一致(sequentially consistent)。当C++标准库禁止通过(其他)线程访问修改对象指的就是这节。

2. const 和 mutable对于共享变量来说意味着什么?
     从C++11开始,变量加上const可能共享对于并发来说,意思是“只读或几乎和只读一样”。在同一对象上的并发const操作要求在没有调用代码做外部同步是安全的。如果你在实现一个类型,除非你知道这个类型的对象绝不会被共享(通常不可能),这几意味着你的每一个const成员函数必须满足其下一点:

· 这个对象真正的是物理上/按位的const,意味着在对象的数据上不执行写动作;
   · 内部同步,这样如果在对象的数据上做了写的动作,那么数据可以通过mutex或者同等性质的(或者是atomic<>)来保证数据的正确性,因此任何可能多调用的并发const访问都不能辨别其中的差别。(相同的)

类型没有遵循以上任意其中一点,那么都不能和标准库一起使用。详细参照ISO C++ §17.6.5.9

同样地,在mutable的成员变量上写总意味着:此变量是“可写的但逻辑上是const的”。这意味着:

·“逻辑上const”部分的意思是“可以被多个并发const操作安全地使用”;
       ·”mutable“和”可写性“部分的意思是一些const操作可能确实会对共享变量进行写的动作,这意味着在对变量进行读和写是内在正确的,因此它应该使用mutex或相同的东西来保护,或者使用atomic<>。

通常情况下:

Guideline:记住”M&M规则“:对于成员变量来说,mutable和mutex(或atomic)是一起使用的。

这是双向的,也就是:
     ·(1)对于成员变量,mutable意味着mutex(或等价物):一个mutable的成员变量假定是一个可变的共享变量,因此必须是内在同步的,使用mutex,称atomic或者同类的东西来保护。
     ·(2)对于成员变量,mutex(或同等的同步类型)意味着mutable:一个成员变量它本身是同步类型,比如mutex或条件变量(condition variable),自然地需要mutable,因为你可能会在并发的const成员函数中以非const的方式来使用它(比如:使用std::lock_guard<mutex>)

我们或在GotW #6b的第二部分看到例子。

3. 在C++98和C++11两者间,const 和 mutable有什么区别?

首先澄清一点:C++98单线程代码依旧是能正常运行的。C++11对C++98有相当好的兼容,即使是在const的语义上有着进化。C++98单线程代码使用老的”逻辑const“意味着const依然是有效的。

随着C++98,我们告诫一整代C++开发者,”const意味的是逻辑上的const,不是物理上/按位的const“。这也就是,在C++98中,我们教授的是const只意味着对象的可观察状态(就是说,通过非private成员函数)不应该改变直到调用者调用。但是它的内部位可能是改变了的,为了更新计数器和一些设施,其他数据通过类型的public或protected接口是不能访问的。

这些定义对于并发来说是不够的。在C++11和之后的版本中,标准库中包含了并发的内存模型和线程安全规范。这也使得更简单一些:现在const真的是意味着”只读“或安全的并发读取,要不真正在物理上/按位const,或者内部同步。因此对于任意可能的并发const访问的写都是同步的,这样调用者就不会知道其中存在不同。

尽管已存在的C++98年代的类型在C++98年代的单线程中依旧能运行正常,这些类型和一些你现在所编写的类型都应该遵循新的更严格的要求,如果它们可能用在多线程中。好消息是那么已经存在的类型已经遵循了这个规则。在单线程中依赖于强制去掉const和/或使用mutable的数据成员已经被普遍质疑和罕见。

原文地址:http://herbsutter.com/2013/05/24/gotw-6a-const-correctness-part-1-3/

[译]GotW #6a: Const-Correctness, Part 1的更多相关文章

  1. [译]GotW #6b Const-Correctness, Part 2

         const和mutable对于书写安全代码来说是个很有利的工具,坚持使用它们. Problem Guru Question 在下面代码中,在只要合适的情况下,对const进行增加和删除(包括 ...

  2. [译]GotW #4 Class Mechanics

    你对写一个类的细节有多在行?这条款不仅注重公然的错误,更多的是一种专业的风格.了解这些原则将会帮助你设计易于使用和易于管理的类. JG Question 1. 什么使得接口“容易正确使用,错误使用却很 ...

  3. [译]GotW #3: Using the Standard Library (or, Temporaries Revisited)

    高效的代码重用是良好的软件工程中重要的一部分.为了演示如何更好地通过使用标准库算法而不是手工编写,我们再次考虑先前的问题.演示通过简单利用标准库中已有的算法来避免的一些问题. Problem JG Q ...

  4. [译]GotW #2: Temporary Objects

        不必要的和(或)临时的变量经常是罪魁祸首,它让你在程序性能方面的努力功亏一篑.如何才能识别出它们然后避免它们呢? Problem JG Question: 1. 什么是临时变量? Guru Q ...

  5. [译]GotW #89 Smart Pointers

    There's a lot to love about standard smart pointers in general, and unique_ptr in particular. Proble ...

  6. [译]GotW #1: Variable Initialization 续

    Answer 2. 下面每行代码都做了什么? 在Q2中,我们创建了一个vector<int>且传了参数10和20到构造函数中,第一种情况下(10,20),第二种情况是{10, 20}. 它 ...

  7. [译]GotW #1: Variable Initialization

    原文地址:http://herbsutter.com/2013/05/09/gotw-1-solution/ 第一个问题强调的是要明白自己在写什么的重要性.下面有几行简单的代码--它们大多数之间都有区 ...

  8. [译]GotW #5:Overriding Virtual Functions

       虚函数是一个很基本的特性,但是它们偶尔会隐藏在很微妙的地方,然后等着你.如果你能回答下面的问题,那么你已经完全了解了它,你不太能浪费太多时间去调试类似下面的问题. Problem JG Ques ...

  9. Meaning of “const” last in a C++ method declaration?

    函数尾部的const是什么意思? 1 Answer by Jnick Bernnet A "const function", denoted with the keyword co ...

随机推荐

  1. HW--漂亮度2(测试通过)

    总结:几个函数的使用 (1)  int num=Integer.parseInt(str[0]); //将第一个字符串转成整形数,表示名字个数 (2) String string1=str[i].to ...

  2. Install GTK in Ubuntu

    reference: http://www.cnblogs.com/niocai/archive/2011/07/15/2107472.html 一.安装 1.安装gcc/g++/gdb/make 等 ...

  3. PL/SQL Developer 使用中文条件查询时无数据的解决方法

    PL/SQL Developer 使用中文条件查询时无数据,这是由于字符集的不一致导致的. 执行以下sql命令:select userenv('language') from dual; 显示:SIM ...

  4. 一个layer可以跟着画完的线移动ios程序 好玩啊。

    用法:采用的是关键帧实现的. 实验目的:让上层的layer子层能够跟着在另一个子层上花的线进行移动 .即当线画完之后,图形开始移动,并且能够停在最后的那个位置 效果图: 采用是直接在layer图层上进 ...

  5. 线程间通信--生产者消费者 升级版JDK5

    import java.util.concurrent.locks.*; /*1.新的解锁,上锁操作,据说是jdk5.0升级版,以前的枷锁,解锁都是隐藏的,默认的,现在变成显式 2.新的异常处理方式  ...

  6. forever start Error: Cannot find module './daemon.v0.10.26'

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3590158.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  7. OpenJudge 2754 八皇后

    1.链接地址: http://bailian.openjudge.cn/practice/2754 2.题目: 总时间限制: 1000ms 内存限制: 65536kB 描述 会下国际象棋的人都很清楚: ...

  8. <<深入Java虚拟机>>-第二章-Java内存区域-学习笔记

    Java运行时内存区域 Java虚拟机在运行Java程序的时候会将它所管理的内存区域划分为多个不同的区域.每个区域都有自己的用途,创建以及销毁的时间.有的随着虚拟机的启动而存在,有的则是依赖用户线程来 ...

  9. MySQL中,修改表的某一字段的部分值

    语法:update 表名 set 字段名 = replace(字段名,'替换前内容','替换后的内容') where 条件. 如: 执行sql语句:update student set name = ...

  10. JavaScript 继承的几种模式

    /** * Created by 2016 on 2016/6/5. */ //1.原型链继承 //把子类的原型,定义为超类的实例 通过原型来访问超类的方法和属性 function Person(){ ...