gpt4 book ai didi

c++ - 使用 std::launder 从指向非事件 union 成员的指针获取指向事件 union 成员的指针?

转载 作者:可可西里 更新时间:2023-11-01 17:44:02 28 4
gpt4 key购买 nike

考虑这个 union :

union A{
int a;
struct{
int b;
} c;
};

ca不是 layout-compatibles类型,因此无法读取 b 的值通过a :

A x;
x.c.b=10;
x.a+x.a; //undefined behaviour (UB)

对于试验 1 和试验 2,请参阅 this question

试验 3

现在让我们使用std::launder对于它似乎不是故意的:

A x;
x.a=10;
auto p = &x.a; //(1)
x.c.b=12; //(2)
p = std::launder(p); //(2')
*p+*p; //(3) UB?

可以 std::launder改变什么?根据[ptr.launder] :

template <class T> constexpr T* launder(T* p) noexcept;

Requires: p represents the address A of a byte in memory. An object X that is within its lifetime and whose type is similar to T is located at the address A. All bytes of storage that would be reachable through the result are reachable through p (see below).

Returns: A value of type T * that points to X.

Remarks: An invocation of this function may be used in a core constant expression whenever the value of its argument may be used in a core constant expression. A byte of storage is reachable through a pointer value that points to an object Y if it is within the storage occupied by Y, an object that is pointer-interconvertible with Y, or the immediately-enclosing array object if Y is an array element. The program is ill-formed if T is a function type or cv void.

加粗的句子强调了一件困扰我的事情。如果p是一个无效的指针值,如何可以访问存储的任何字节?另一方面,这样的阅读std::launder就是不可用。

否则,可以p在 (2) 处的值是一个指针值,表示存储区域,如 [basic.life] 中的“注释”中所述。 :

If these conditions are not met, a pointer to the new object can be obtained from a pointer that represents the address of its storage by calling std​::​launder ([support.dynamic]).

最佳答案

注释中明确允许。

basic.life contains the following rule这使得 std::launder 变得不必要了:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

  • the storage for the new object exactly overlays the storage location which the original object occupied, and
  • the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
  • the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
  • neither the original object nor the new object is a potentially-overlapping subobject.

[ Note: If these conditions are not met, a pointer to the new object can be obtained from a pointer that represents the address of its storage by calling std::launder. — end note ]

这种“新对象在原始对象占用的存储位置创建”的情况显然适用于此,因为:

An object is created ... when implicitly changing the active member of a union...

满足所有项目符号条件,如"potentially overlapping subobject"指的是基类子对象, union 成员不是。 (在您链接到的版本中,该项目符号直接提到了基类子对象。)

然而,即使这个解释要针对 union 而改变,该注释特别提到 std::launder 绕过了这个限制。

请注意,旧版本的标准从该规则中排除了子对象......但注释清楚地表明 std::launder 也可以绕过该问题。

关于c++ - 使用 std::launder 从指向非事件 union 成员的指针获取指向事件 union 成员的指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56308110/

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