gpt4 book ai didi

c++ - 我们可以访问一个不存在的联盟的成员吗?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:32:41 24 4
gpt4 key购买 nike

在 c++ 标准中,在 [basic.lval]/11.6 中说:

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:[...]

  • an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),[...]

这句话是严格别名规则的一部分。

它能让我们访问一个不存在的联盟的非活跃成员吗?如:

struct A{
int id :1;
int value :32;
};
struct Id{
int id :1;
};

union X{
A a;
Id id_;
};

void test(){
A a;
auto id = reinterpret_cast<X&>(a).id_; //UB or not?
}

注意:下面解释了我在标准中没有掌握的内容,以及为什么上面的示例可能有用。

我想知道 [basic.lval]/11.6 有什么用。

[class.mfct.non-static]/2确实禁止我们调用“转换为” union 或聚合的成员函数:

If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.

考虑到可以使用限定名称 (a_class::a_static_member) 直接执行静态数据成员访问或静态成员函数,[basic.lval]/11.6 唯一有用的用例可能是访问“casted to”联盟的成员。我考虑过使用最后一个标准规则来实现“优化变体”。此变体可以包含 A 类对象或 B 类对象,这两个对象以大小为 1 的位域开头,表示类型:

class A{
unsigned type_id_ :1;
int value :31;
public:
A():type_id_{0}{}
void bar{};
void baz{};
};

class B{
unsigned type_id_ :1;
int value :31;
public:
B():type_id_{1}{}
int value() const;
void value(int);
void bar{};
void baz{};
};

struct type_id_t{
unsigned type_id_ :1;
};

struct AB_variant{
union {
A a;
B b;
type_id_t id;};
//[...]
static void foo(AB_variant& x){
if (x.id.type_id_==0){
reinterpret_cast<A&>(x).bar();
reinterpret_cast<A&>(x).baz();
}
else if (x.id.type_id_==1){
reinterpret_cast<B&>(x).bar();
reinterpret_cast<B&>(x).baz();
}
}
};

调用 AB_variant::foo 不会调用未定义的行为,只要它的参数引用类型为 AB_variant 的对象,这要归功于指针互换性规则[basic.compound]/4 .允许访问未激活的 union 成员 type_id_,因为 id 属于 Acommon initial sequenceBtype_id_t [class.mem]/25 :

但是如果我尝试用 A 类型的完整对象调用它会发生什么?

A a{};
AB_variant::foo(reinterpret_cast<AB_variant&>(a));

这里的问题是我试图访问一个不存在的 union 的非事件成员。

两个相关的标准段落是[class.mem]/25 :

In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.

[class.union]/1 :

In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended.

Q3:“其名所指”是否表示“一个对象”实际上是一个构建在活 union 体中的对象?或者它可以引用对象 a 因为 [basic.lval]/11.6。

最佳答案

[expr.ref]/4.2如果 E2 是非静态数据成员,则定义 E1.E2 的含义:

If E2 is a non-static data member [...], the expression designates the named member of the object designated by the first expression.

这仅为第一个表达式实际指定对象的情况定义了行为。由于在您的示例中,第一个表达式未指定任何对象,因此该行为因遗漏而未定义;见[defns.undefined] (“当本文档省略任何明确的行为定义时,可能会出现未定义的行为……”)。


您还误解了严格别名规则中“访问”的含义。它的意思是“读取或修改对象的值”([defns.access])。命名非静态数据成员的类成员访问表达式既不读取也不修改任何对象的值,因此不是“访问”,因此永远不会有“访问...通过”“聚合或 union ”的泛左值类型”,因为类成员访问表达式。

[basic.lval]/11.6 本质上是从 C 复制的,它实际上意味着某些东西,因为分配或复制 structunion 会访问整个对象。它在 C++ 中毫无意义,因为类类型的赋值和复制是通过特殊成员函数执行的,这些成员函数要么执行成员复制(因此单独“访问”成员),要么对对象表示进行操作。参见 core issue 2051 .

关于c++ - 我们可以访问一个不存在的联盟的成员吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53151044/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com