当前位置: 首页 > 知识库问答 >
问题:

丢弃的volatile类类型的值表达式与volatile内置类型的值表达式的行为不同

陈增
2023-03-14

请考虑以下代码:

struct S{
  int i;
  S(int);
  S(const volatile S&);
  };

struct S_bad{
  int i;
  };

volatile S     as{0};
volatile S_bad as_bad{0};
volatile int   ai{0};

void test(){
   ai;     //(1)=> a load is always performed
   as;     //(2)=> Should call the volatile copy constructor
   as_bad; //(3)=> Should be ill-formed
   }

表达式ai;as;as_bad是被丢弃的值表达式,根据C++标准草案N4659/[expr].12,我希望lvalue-to-rvalue将应用于这三种情况。对于情况(2),这将导致调用volatile复制构造函数(s(const volatile s&))[expr]/12

[...]如果表达式在此可选转换后是prvalue,则应用临时物化转换([Conv.RVAL])。[注意:如果表达式是类类型的lvalue,则它必须有一个易失性的复制构造函数来初始化作为lvalue-to-rvalue转换的结果对象的临时值。-结束注意]

所以情况(3)应该是不正确的。

>

  • GCC:

    • AI;=>加载AI的值;
    • 作为;=>不生成代码,不发出警告;
    • as_bad;=>加载as_bad.i.

    Clang不为case(2)生成加载,并生成警告:expression result unused;赋值到一个变量以强制执行volatile加载[-wunused-volatile-lvalue]

      null
      null
    • AI;=>加载AI的值;
    • as;=>调用s(const volatile s&)并将as作为参数;
    • as_bad;=>生成编译错误

    我对标准的解释对吗?如果有的话,哪个编译器是正确的?

  • 共有1个答案

    柏麒
    2023-03-14
    1. C++03表示表达式语句的结果不会发生lvalue-to-rvalue转换,也没有明确表示在转换发生时会发生副本。
    2. C++11表示,如您所述,转换确实发生在易失性对象上,并且转换涉及复制以临时创建。
    3. C++14只是清理了措辞(以避免像b?(x,y):z这样的愚蠢事情,如果y做了就不计算),并添加了关于易失性复制构造函数的注释。
    4. C++17应用临时物化转换以保留先前的含义。

    所以我的结论是(从C++11)你是正确的,所有编译器都是错误的。特别是,除非复制构造函数读取s::i加载,否则不应该发生加载。当然,“访问”的实现定义性质与什么是良好形式的问题无关;它只影响是否实际生成了ai的加载指令。存在s_bad是聚合的问题,但这是不相关的,因为它不是列表初始化的。

     类似资料:
    • 如果我以通常的方式声明一个类,我可以使用类名作为类型: 但是,如果我通过将类表达式分配给变量来声明一个类,我就不能将该名称用作类型: 建议使用不起作用,因为我想要的实例类型,而不是类本身的类型。 typescript操场示例 如何获取以第二种方式定义的类的实例类型? 我对以这种方式定义类感兴趣的原因是,我希望有一个接口来描述某些类将具有的静态方法,如此处的手册中所述(该部分中的第三个示例)。 下面

    • 问题内容: 我正在将此问题设置为“ FizzBu​​zz”,而我的switch语句给了我一些问题,这是我的代码: 如果您可以为我提供指针/提示,而不是给我正确的代码,那将是一件好事:D我宁愿自己解决它,但一些提示也可以使我摆脱困境。 问题答案: 您可以在单独检查它们之前使用并检查两者是否匹配:

    • 在我将PostgreSQL 13个数据库列标记更改为jsonb后,执行sql时抛出错误: 在使用mybatis时,我应该如何处理spring boot应用程序中的jsonb?

    • 在Spring Boot的一个项目中,Java8使用hibernate-spatial和PostgresDB 9.4 应用程序属性 (我也尝试了PostgisPG9Dialect) 我的实体有一个属性 如果我用空值保存就可以了,但是如果我放一个值 我有: 在我的数据库中,我可以看到列定义为 我要疯了...为什么它不起作用? 更新(仍然不起作用,我正在收集新信息) 1)我认为问题可能是数据库的创建。

    • 问题内容: 警告让我有些困惑,因为我的Eclipse IDE当前正在将类型自动装箱或自动拆箱的每个表达式旁边写入: 这是我应该做出反应的警告吗?我认为自动装箱是Java语言的功能-但是现在每次使用此功能时,我似乎都会收到警告。 问题答案: 我不认为Eclipse默认情况下不会这样做(我的不是),但是您可以使用“偏好设置”>“ Java”>“编译器”>“错误/警告”>“潜在的编程问题”>“装箱和拆箱

    • decltype(E)是一个标识符或者表达式的推断数据类型(“declared type”),它可以用在变量声明中作为变量的数据类型。例如: void f(const vector<int>& a, vector<float>& b) { // 推断表达式a[0]*b[0]的数据类型,并将其定义为Temp类型 typedef decltype(a[0]*b[0]) Tmp;