【问题标题】:Union containing volatile structs包含 volatile 结构的联合
【发布时间】:2015-02-05 01:53:52
【问题描述】:

这似乎类似于POD structs containing constant member,但有点相反。

#include <iostream>

struct A
{
    int a;
};

union U
{
    volatile A a;
    long b;
};

int main()
{
    U u1;
    U u2;

    u1.a.a = 12;
    u2 = u1;
    std::cout << u2.a.a << std::endl;

    return 0;
}

g++ 4.8.3 编译这段代码没有错误并且运行正常:

$ g++ -std=c++03 a.cpp -o a_gcc
$ ./a_gcc
12

但是 clang++ 3.5.1 会产生错误(我已经手动包装了错误消息以防止代码框滚动):

$ clang++ -std=c++03 a.cpp -o a_clang
a.cpp:8:7: error: member function 'operator=' not viable: 'this'
argument has type 'volatile A', but function is not marked volatile
union U
      ^
a.cpp:3:8: note: 'operator=' declared here
struct A
       ^
a.cpp:20:5: note: implicit copy assignment operator for 'U' first
required here
        u2 = u1;
        ^
1 error generated.

C++03 是否允许程序复制分配包含 volatile 结构的联合?我在 C++03 标准中找不到任何定义联合的默认复制构造函数的内容。

我想知道哪个编译器是正确的,或者标准在这一点上是否不明确。

编辑:我发现如果我使用复制构造而不是复制赋值,clang++ 和 g++ 都将编译程序而不会出错。具体来说,如果我将main 更改为:

int main()
{
    U u1;

    u1.a.a = 12;
    U u2 = u1;
    std::cout << u2.a.a << std::endl;

    return 0;
}

.. 然后它会工作。我想知道为什么 clang++ 对它们的处理方式不同。

【问题讨论】:

  • 如果在union U:volatile U&amp; operator =(const volatile U&amp;) volatile中添加一个用户定义的赋值运算符呢?或者也许只有其中一些volatiles?
  • 为什么不让工会的实例变得易变,而不是让工会的成员成为易变的?用这种方式推断它的行为似乎更容易。
  • @JohnZwinck 因为那样就不会导致这个问题了。

标签: c++ language-lawyer volatile unions c++03


【解决方案1】:

在 C++11 中,可以删除联合的复制构造函数。我们从 [class.union] 中的注释中看到这一点,N4140 中的 §9.5:

[注意:如果有任何非静态数据成员 联合的有一个重要的默认构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8), 复制赋值运算符 (12.8)、移动赋值运算符 (12.8) 或析构函数 (12.4),对应的 联合的成员函数必须是用户提供的,否则它将为联合隐式删除(8.4.3)。 ——尾注]

在 [class.copy], §12.8/25 中,我们看到我们的 union 有一个重要的复制构造函数:

类 X 的复制/移动赋值运算符如果不是用户提供的,则它是微不足道的,它的参数类型列表是 相当于隐式声明的参数类型列表,如果 ...
— [ .. ]
— X 类没有 volatile 限定类型的非静态数据成员,并且

但是 [class.copy] 中的特定行只是添加了 Is a volatile-qualified type really a POD? 的结果在此之前,这样的类仍然会被认为具有微不足道的复制构造函数。

所以我的理解是,在 C++03 中,没有迹象表明应该删除联合的复制构造函数,而在 C++11 中,有一些迹象表明这一点,但它是非规范的。

【讨论】:

  • 请注意,您引用的规则实际上并不适用,因为它是联合本身,其复制分配运算符是不平凡的,但该规则讨论了成员的运算符......和副本class A 的赋值运算符 微不足道。
  • @BenVoigt 嗯。然后我什么都没得到。
  • 我认为这仍然很有价值,但绝对不规范。
  • @Barry 对 C++11 的有趣参考。如果我在 C++11 模式下编译我的测试程序,g++ 和 clang++ 都会出错,即隐式删除 U 的复制赋值运算符。
  • @Barry 对于 C++11,我认为相关引用是“类类型 M(或其数组)的非静态数据成员,由于重载决议(13.3)而无法复制/移动,应用于 M 的相应赋值运算符时,会导致歧义或函数从默认赋值运算符中删除或无法访问,或者 ..." 来自 12.8/24。不能使用成员的默认复制赋值运算符,因为默认的复制赋值运算符不能处理 volatile(参见 12.8/19 及其脚注)。但这仅适用于 C++11,我还没有找到 C++03 的任何东西
猜你喜欢
  • 1970-01-01
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 2020-10-14
相关资源
最近更新 更多