复制与自动生成的操作员=

问题描述 投票:0回答:1

在以下程序中,

union U
具有类型的活性成员,该成员是使用自动生成的
A
复制到类型
operator =
的另一个成员中的,将
B
作为subobject:
A

我想获得
#include <iostream>

struct A { char c[7]; };

struct X { char x; };

struct B : X, A {
    using A::operator=;
};

int main() {
    union U {
        A a{ 0, 1, 2, 3, 4, 5, 6 };
        B b;
    } u;
    
    //#1
    u.b = u.a;

    //#2
    //u.b = A( u.a );

    for ( int i = 0; i < 7; ++i )
        std::cout << (int)u.b.c[i];
}
输出,但是没有优化的实际编译器会产生不同的输出。

MSVC:
0123456

  • clang:
    0000000
  • GCC和EDG:
    0123355
  • 问题1:是因为该程序在复制过程中同时访问了联盟的活动和不活动成员,因此该程序具有不确定的行为?
    
    如果不是
  • 0122356
,我首先创建一个临时副本,然后使用

u.b = u.a;

分配,然后MSVC和Clang的结果预期

u.b = A( u.a );

,但是GCC和EDG坚持使用相同的
0123456
。在线演示:
https://gcc.godbolt.org/z/dxfzem5em

问题2:该程序现在是否形成良好,意外结果是由于实现中的错误造成的吗?
    
在一个给定时刻(

[class.union.general]/2

)的联合中,最多有一个成员可以活跃(寿命内)。

升级
c++ c++11 language-lawyer union
1个回答
0
投票
隐式启动

u.b = u.a成员的寿命,从而结束了b

[basic.life]/2.5

)的寿命。根据[class.union.general]/5

...(对于创建对象)没有执行初始化,并且其生命周期的开始是在左右操作数的值计算之后和分配之前对其进行测序的。
在分配发生的时间,u.a不在一生之内,因此从中读取的行为不确定。 在对比中,在tempor临时对象的初始化中发生在u.a

仍处于活动状态时,避免了生命周期的问题并使分配明确定义。
worth指出,上述措辞首先仅出现在C ++ 17中(起源于

P0137

)。在此之前,工会与对象寿命的相互作用在很大程度上未指定,因此基于C ++ 11的规范文本,可能没有确定的答案。但是,[class.union]中的一个
示例似乎表明,通过分配的主动联盟成员的隐式变化至少也旨在在当时有效。


最新问题
© www.soinside.com 2019 - 2025. All rights reserved.