c++中的volatile和variant关键字详解

目录
  • 一、两个长得有点像的变量
  • 二、二者的功能
  • 三、应用实例
  • 四、总结

一、两个长得有点像的变量

对volatile关键字,其实很多人只是能用,知道用到啥处,但其实应用的原理并不知道。在一些多线程的通信中,往往是这个关键字应用到的场所,很多人也是如此想的。但其实这个想法是不准确的。volatile这个关键字的目的最初是针对硬件IO操作的,防止访问IO操作中的缓存影响到真实的数据。但这个关键字的溢出效应是,多线程也可以应用这个原理(注意在多核和多CPU编程中有危险,但是在其它语言如Java中,得按具体的语言规范来决定),那么反而在硬件IO中的应用成了一种比较少的应用场景。
在c++17中,还有一个长得和它类似的联合体variant,如果有其它语言中var变量的使用,就大概明白了这是个啥玩意儿。既然是联合体,那么就明白了这个关键字的用处了,也就是说,它可以表示明确的类型定义,而在前面提到的std::any则不是。看一下在c++17中它的标准定义:

template <class... Types>
class variant;

之所以把它们两个搞在一起,是有的时候儿新手小菜鸟可能会把两个傻傻分不清。

二、二者的功能

类模板 std::variant 表示一个类型安全的联合体,它表示可以拥有其中的任何一个类型或者无值,它不能保有引用、数组或者void,如果表示一个空值,也要用std::variantstd::monostate 代替。同样,在默认构造时,默认保有联合体的第一个类型。面std::volatile则更多倾向于一个编译器的优化选项处理,它会防止变量被编译器缓存。正如前面所讲,这个在多线程中应用的比较多,但其实他更安全的应用其实是在硬件IO操作中。
这么看来,这二者的区别还是相当明显的,别看长得乍一看有点像,但还真不是一嘛事儿。只要写一回代码估计就记清楚了。或者简单的记忆成volatile是一个关键字,而variant是一个复合类型,是一个联合体,是一个类模板。

三、应用实例

看一个variant的例程:

#include <variant>
#include <string>
#include <cassert>

int main()
{
    std::variant<int, float> v, w;
    v = 12; // v 含 int
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // 与前一行效果相同
    w = v; // 与前一行效果相同

//  std::get<double>(v); // 错误: [int, float] 中无 double
//  std::get<3>(v);      // 错误:合法下标值为 0 与 1

    try {
      std::get<float>(w); // w 含 int 而非 float :将抛出
    }
    catch (const std::bad_variant_access&) {}

    using namespace std::literals;

    std::variant<std::string> x("abc"); // 转换构造函数在无歧义时起作用
    x = "def"; // 转换赋值在无歧义时亦起作用

    std::variant<std::string, void const*> y("abc");
    // 传递 char const * 时转换成 void const *
    assert(std::holds_alternative<void const*>(y)); // 成功
    y = "xyz"s;
    assert(std::holds_alternative<std::string>(y)); // 成功
}

volatitle这个关键字给一个判断的例程,就不给多线程的例程了,这玩意儿一般来说还是要小心使用,在多核,内存序未知的情况下,还是不用为妙,X86因为一些历史原因,用起来还是比较可以接受的:

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << boolalpha;
    std::cout << std::is_volatile<int>::value << '\n';
    std::cout << std::is_volatile<volatile int>::value  << '\n';
}

这个关键字对从Java转过来的开发人员可能有非常大的迷惑性,二者的理解意义还是有比较大的不同的。把内存序掌握好了,就知道为什么在X86的PC上跑一般没有问题的原因,如果还是无法清楚,就好好看看c++标准中对内存序的支持。这个一定要搞明白,搞不明白的话,可能不会影响到编程,但会影响到对标准的认知。

四、总结

俗话说:“看一遍不如写一遍”,这句话在计算机行业应该是非常合适的。计算机技术是一门理论科学与实践高度结合的技术,理论是源泉,实践是根本,互相反馈,不断迭代,这才是真正提高编程水平的王道。
努力吧,归来的少年

到此这篇关于c++中的volatile和variant关键字详解的文章就介绍到这了,更多相关c++ volatile和variant关键字内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中volatile关键字及常见的误解总结

    前言 近期看到C++标准中对volatile关键字的定义,发现和java的volatile关键字完全不一样,C++的volatile对并发编程基本没有帮助.网上也看到很多关于volatile的误解,于是决定写这篇文章详细解释一下volatile的作用到底是什么. 为什么用volatile? C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier.这是 BS 在 "The C++ Programming Language&

  • 使用c++11打造好用的variant方法

    boost中的variant的基本用法: 复制代码 代码如下: typedef variant<int,char, double> vt;vt v = 1;v = '2';v = 12.32; 用variant一个好处是可以擦除类型,不同类型的值都统一成一个variant,虽然这个variant只能存放已定义的类型,但这在很多时候已经够用了. 取值的时候,通过get<T>(v)来获取真实值.然而,当T类型与v的类型不匹配时,会抛出一个bad_cast的异常来.boost的varia

  • c++中的volatile和variant关键字详解

    目录 一.两个长得有点像的变量 二.二者的功能 三.应用实例 四.总结 一.两个长得有点像的变量 对volatile关键字,其实很多人只是能用,知道用到啥处,但其实应用的原理并不知道.在一些多线程的通信中,往往是这个关键字应用到的场所,很多人也是如此想的.但其实这个想法是不准确的.volatile这个关键字的目的最初是针对硬件IO操作的,防止访问IO操作中的缓存影响到真实的数据.但这个关键字的溢出效应是,多线程也可以应用这个原理(注意在多核和多CPU编程中有危险,但是在其它语言如Java中,得按

  • C#中的const和readonly关键字详解

    const和readonly经常被用来修饰类的字段,两者有何异同呢? const 1.声明const类型变量一定要赋初值吗? 一定要赋初值 public class Student { public const int age; } 生成的时候,会报如下错: 正确的应该这样写: public class Student { public const int age = 18; } 2.声明const类型变量可以用static修饰吗? 不可以 public class Student { publ

  • Java中Volatile关键字详解及代码示例

    一.基本概念 先补充一下概念:Java内存模型中的可见性.原子性和有序性. 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情.为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.也就是一个线程修改的结果.另一个线程马上就能看到.比如:用volatile修饰的变量,就会具有可见性.volatile修饰的

  • Java中final关键字详解

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法. 主要介绍:一.final关键字的基本用法.二.深入理解final关键字 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量).下面就从这三个方面来了解一下final关键字的基本用法. 1.修饰类 当用final修饰一个类时,表明这个类不能

  • C/C++ 中extern关键字详解

    C/C++ 中extern关键字详解 在C/C++编程过程中,经常会进行变量和函数的声明和定义,各个模块间共用同一个全局变量时,此时extern就派上用场了. 定义 extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义,不需要分配内存,直接使用. 推荐:在.h中声明,因为在头文件定义的话,其他模块include此头文件,就会报重复定义错误 实验结论 1.在.h中声明 extern int g_a; 在.c中定义 int g_

  • Java中final关键字详解及实例

    final在Java中可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,如果你试图将变量再次初始化的话,编译器会报编译错误.  final的含义在不同的场景下有细微的差别,但总体来说,它指的是"不可变". 1. final变量 凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为final的都叫作final变量.final变量经常和static关键字一起使用,作为常量.用final关键字修饰的变量,只能进行一次赋值操作

  • Java中super和this关键字详解

    目录 父类空间优先于子类对象产生 super和this的含义 super和this的用法 继承的特点 父类空间优先于子类对象产生 在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身.目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员.代码体现在子类的构造方法调用时,一定先调用父类的构造方法. 理解图解如下:  super和this的含义 super :代表父类的存储空间标识(可以理解为父亲的引用). this

  • C++中的explicit关键字详解

    目录 前言 1. 抑制构造函数定义的隐式转换 2. 为转换显式地使用构造函数 3. 类型转换运算符可能产生意外结果 4. 显示的类型转换运算符 5. explicit练习 5.1 当不使用explict关键字时 5.2 使用explict关键字时 5.3 explicit 标识的构造函数中存在一个默认值 前言 最近在阅读android底层源码的时候,发现其中好多代码使用了explicit关键字,因此这里对explicit关键字进行了分析和介绍. 1. 抑制构造函数定义的隐式转换 在要求隐式转换的

  • PHP中的函数声明与使用详解

      函数 1.  函数名是标识符之一,只能有字母数字下划线,开头不能是数字: 函数名的命名,必须符合"小驼峰法则"FUNC(),func(),Func(); 函数名不区分大小写; 函数名不能与已有函数同名,不能与内置函数名同名: 2.   function_exists("func");用于检测函数是否已经声明: 注意传入的函数名,必须是字符串格式,返回结果为true/false: echo打印时,true为1,false不显示:               [ph

  • 基于js中this和event 的区别(详解)

    今天在看javascript入门经典-事件一章中看到了 this 和 event 两种传参形式.因为作为一个初级的前端开发人员平时只用过 this传参,so很想弄清楚,this和event的区别是什么,什么情况下用什么比较合适. onclick = changeImg(this)       vs     onclick = changeImg(event) <img src='usa.gif' onclick="changeImg(event)" /> <scrip

随机推荐