[英]std::launder use cases in C++20
[1] [1]
Are there any cases in which the addition of p0593r6 into C++20 ( § 6.7.2.11 Object model [intro.object] ) made std::launder
not necessary, where the same use case in C++17 required std::launder
, or are they completely orthogonal ? Are there any cases in which the addition of p0593r6 into C++20 ( § 6.7.2.11 Object model [intro.object] ) made
std::launder
not necessary, where the same use case in C++17 required std::launder
, or它们是完全正交的吗?
[2] [2]
The example in the spec for [ptr::launder] is: [ptr::launder]规范中的示例是:
struct X { int n; };
const X *p = new const X{3};
const int a = p->n;
new (const_cast<X*>(p)) const X{5}; // p does not point to new object ([basic.life]) because its type is const
const int b = p->n; // undefined behavior
const int c = std::launder(p)->n; // OK
Another example is given by @Nicol Bolas in this SO answer , using a pointer that points to a valid storage but of a different type: @Nicol Bolas在此 SO answer中给出了另一个示例,使用指向有效存储但类型不同的指针:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
Are there other use cases, not related to allowing casting of two objects which are nottransparently replaceable , for using std::launder
?是否有其他用例,与允许投射两个不可透明替换的对象无关,用于使用
std::launder
?
Specifically:具体来说:
std::launder
in any case? std::launder
吗? (ie can two pointers be pointer-interconvertible and yet not be transparently replaceable ? the spec didn't relate between these two terms). std::launder
? std::launder
?std::launder
?std::launder
? If so, under which case in the spec does it fall to require that? A struct with reference member, inspired by this discussion :受此讨论启发的具有引用成员的结构:
struct A {
constexpr A(int &x) : ref(x) {}
int &ref;
};
int main() {
int n1 = 1, n2 = 2;
A a { n1 };
a.~A();
new (&a) A {n2};
a.ref = 3; // do we need to launder somebody here?
std::cout << a.ref << ' ' << n1 << ' ' << n2 << std::endl;
}
Before C++17, a pointer with a given address and type always pointed to an object of that type located at that address, provided that the code respects the rules of [basic.life].在 C++17 之前,具有给定地址和类型的指针始终指向位于该地址的该类型的 object,前提是代码遵守 [basic.life] 的规则。 (see: Is a pointer with the right address and type still always a valid pointer since C++17? ).
(请参阅: 自 C++17 以来,具有正确地址和类型的指针是否仍然始终是有效指针? )。
But in the C++17 standard added a new quality to a pointer value.但是在 C++17 标准中为指针值添加了新的质量。 This quality is not encode within the pointer type but qualifies directly the value, independently of the type (this is the case also of the traceability).
这种质量不是在指针类型中编码,而是直接限定值,与类型无关(这也是可追溯性的情况)。 It is described in [basic.compound]/3
它在[basic.compound]/3中有描述
Every value of pointer type is one of the following:
指针类型的每个值都是以下之一:
a pointer to an object or function (the pointer is said to point to the object or function), or
指向 object 或 function 的指针(据说该指针指向 object 或函数),或
a pointer past the end of an object ([expr.add]), or
超过 object ([expr.add]) 末尾的指针,或
the null pointer value for that type, or an invalid pointer value.
该类型的 null 指针值,或无效的指针值。
This quality of a pointer value has its own semantic (transition rules), and for the case of reinterpret_cast
it is described in the next paragraph:指针值的这种性质有其自己的语义(转换规则),对于
reinterpret_cast
的情况,它在下一段中描述:
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast.
如果两个对象是指针可互转换的,那么它们具有相同的地址,并且可以通过 reinterpret_cast 从指向另一个的指针获得指向其中一个的指针。
In [basic-life], we can find an other rule that describes how transitions this quality when an object storage is reused:在 [basic-life] 中,我们可以找到另一条规则,该规则描述了在重用 object 存储时如何转换此质量:
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, [...]
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指原 object,或原 object 的名称将自动指新的 object 和 [...]
As you can see the quality "pointer to an object" is attached to a specific object.如您所见,质量“指向对象的指针”附加到特定的 object。
That means that in the variation bellow of the first example you give, the reinterpret_cast
does not allow us not to use the pointer optimization barrier:这意味着在您给出的第一个示例的以下变体中,
reinterpret_cast
不允许我们不使用指针优化屏障:
struct X { int n; };
const X *p = new const X{3};
const int a = p->n;
new (const_cast<X*>(p)) const X{5}; // p does not point to new object ([basic.life]) because its type is const
const int b = *reinterpret_cast <int*> (p); // undefined behavior
const int c = *std::launder(reinterpret_cast <int*> (p));
A reinterpret_cast
is not a pointer optimization barrier: reinterpret_cast <int*>(p)
points to the member of the destroyed object. reinterpret_cast
不是指针优化屏障: reinterpret_cast <int*>(p)
指向被破坏的 object 的成员。
An other way to conceive it is that the "pointer to" quality is conserved by reinterpret_cast
as long as the object are pointer inter-convertible or if its casted to void and then back to a pointer inter-convertible type.设想它的另一种方式是,只要 object 是指针可相互转换的,或者如果它被强制转换为 void,然后再返回到指针可相互转换的类型,那么
reinterpret_cast
就可以保存“指向”质量。 (See [exp.static_cast]/13 ). (见[exp.static_cast]/13 )。 So
reinterpret_cast <int*>(reinterpret_cast <void*>(p))
still points to the destroyed object.所以
reinterpret_cast <int*>(reinterpret_cast <void*>(p))
仍然指向被破坏的 object。
For the last example you gives, the name a
refers to a non const complete object, so the original a
is transparently replaceable by the new object.对于您给出的最后一个示例,名称
a
指的是非常量完整的 object,因此原始a
可以透明地替换为新的 object。
For the first question you ask: "Are there any cases in which the addition of p0593r6 into C++20 (§ 6.7.2.11 Object model [intro.object]) made std::launder not necessary, where the same use case in C++17 required std::launder, or are they completely orthogonal?"对于您问的第一个问题:“是否有任何情况下将 p0593r6 添加到 C++20 中(§ 6.7.2.11 Object model [intro.object])不需要 std::launder 中的相同用例C++17 需要 std::launder,还是它们完全正交?”
Honestly, I have not been able to find any cases that where std::launder could compensate implict-lifetime objects.老实说,我找不到任何 std::launder 可以补偿隐含生命周期对象的情况。 But I found an example were implicit-lifetime object makes std::launder usefull:
但我发现一个例子是隐式生命周期 object 使 std::launder 有用:
class my_buffer {
alignas(int) std::byte buffer [2*sizeof(int)];
int * begin(){
//implictly created array of int inside the buffer
//nevertheless to get a pointer to this array,
//std::launder is necessary as the buffer is not
//pointer inconvertible with that array
return *std::launder (reinterpret_cast <int(*)[2]>(&buffer));
}
create_int(std::size_t index, int value){
new (begin()+index) auto{value};
}
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.