【发布时间】:2022-12-14 07:31:57
【问题描述】:
我正在修改the cppreference launder 网页上给出的示例。
下面显示的示例表明,要么我误解了某些东西并引入了 UB,要么某处存在错误,或者 clang 是为了松懈或者太好了。
- 在 doit1() 中,我认为 GCC 所做的优化是不正确的(函数返回 2)并且没有考虑到我们使用放置新返回值这一事实。
- 在 doit2() 中,我相信代码也是合法的,但是对于 GCC,没有生成代码?
在这两种情况下,clang 都提供了我期望的行为。在 GCC 上,这取决于优化级别。我试过 GCC 12.1,但这不是唯一显示此行为的 GCC 版本。
#include <new> struct A { virtual A* transmogrify(int& i); }; struct B : A { A* transmogrify(int& i) override { i = 2; return new (this) A; } }; A* A::transmogrify(int& i) { i = 1; return new (this) B; } static_assert(sizeof(B) == sizeof(A), ""); int doit1() { A i; int n; int m; A* b_ptr = i.transmogrify(n); // std::launder(&i)->transmogrify(m); // OK, launder is NOT redundant // std::launder(b_ptr)->transmogrify(m); // OK, launder IS redundant (b_ptr)->transmogrify(m); // KO, launder IS redundant, we use the return value of placment new return m + n; // 3 expected, OK == 3, else KO } int doit2() { A i; int n; int m; A* b_ptr = i.transmogrify(n); // b_ptr->transmogrify(m); // KO, as shown in doit1 static_cast<B*>(b_ptr)->transmogrify(m); // VERY KO see the ASM, but we realy do have a B in the memory pointed by b_ptr return m + n; // 3 expected, OK == 3, else KO } int main() { return doit1(); // return doit2(); }
【问题讨论】:
-
@LanguageLawyer 您引用的段落不适用,因为
A有一个微不足道的析构函数。双重如此,因为A类型的基类子对象也占用相同的存储位置。上面关于B对象如何不能透明地替换A对象的段落是问题所在 -
@Artyer 已删除,同意琐碎。不同意更换。
标签: c++ g++ language-lawyer clang++ stdlaunder