我在哪里可以找到 std::launder 的真正作用? [复制]

Posted

技术标签:

【中文标题】我在哪里可以找到 std::launder 的真正作用? [复制]【英文标题】:Where can I find what std::launder really does? [duplicate] 【发布时间】:2019-04-15 12:34:22 【问题描述】:

我试图了解std::launder 的作用,我希望通过查找示例实现可以清楚地了解。

在哪里可以找到std::launder 的示例实现?

当我查看 lbic++ 时,我看到类似

的代码
  template<typename _Tp>
    [[nodiscard]] constexpr _Tp*
    launder(_Tp* __p) noexcept
     return __builtin_launder(__p); 

这让我觉得这是另一个编译器魔法函数。

这个函数__builtin_launder 可以做什么,它只是添加一个标签来禁止编译器关于别名的警告吗?

是否可以根据__builtin_launder 来理解std::launder,或者它只是更多的编译器魔法(挂钩)?

【问题讨论】:

也许可以帮助gcc.gnu.org/ml/libstdc++/2016-10/msg00194.html 您刚刚提供了一个示例实现 - 我不明白这个问题。你在问what launder is for吗? "我试图了解 std::launder 的作用,我希望通过查找示例实现可以清楚地了解。" 是的,这真的不会告诉你很多关于launder 的工作原理。根据定义,launder 的行为存在于 C++ 正常工作的之外。也就是说,您不能编写launder 的实现。这就像要求实现sizeofoffsetof 也许见en.cppreference.com/w/cpp/utility/launder @alfC:其实你可以自己实现initializer_list。你不能实现的是initializer_list引用的后备数组,它是通过使用braced-init-list生成的。 【参考方案1】:

std::launder 的目的不是“抑制警告”,而是消除 C++ 编译器可能存在的假设。

别名警告试图通知您,您可能正在执行 C++ 标准未定义的行为。

编译器可以并且确实会假设您的代码仅执行标准定义的操作。例如,它可以假设指向 const 值的指针一旦构造就不会改变。

编译器可能会使用该假设跳过从内存中重新获取值(并将其存储在寄存器中),甚至在编译时计算其值并基于它进行死代码消除。它可以假设这一点,因为任何它为假的程序都在执行未定义的行为,因此任何程序行为都在 C++ 标准下被接受。

std::launder 旨在允许您将指针指向真正经过合法修改的const 值(例如,通过在其存储中创建一个新对象)并在之后使用该指针以定义的方式进行修改(因此它指的是新对象)和其他特定和类似的情况(不要假设它只是“消除混叠问题”)。 __builtin_launder 在某种意义上将是一个“noop”函数,但从另一种意义上说,它将改变围绕它可以生成什么样的汇编代码。有了它,就不能对其输出做出关于可以从其输入中获得什么价值的某些假设。一些输入指针上的 UB 代码不是输出指针上的 UB。

这是一个专家工具。我个人不会在没有进行大量标准研究和仔细检查我没有使用错误的情况下使用它。添加它是因为有人证明某些操作无法以符合标准的方式合理执行,并且它允许库编写者现在有效地执行此操作。

【讨论】:

很遗憾,C 和 C++ 标准从一开始就没有标准的内在函数,相当于将指针传递给编译器不知道的函数,但它不知道t 碰巧实际上做了任何事情(使用指针或其他任何东西)。编译器优化包含对使用内在函数的函数的调用的循环的能力将相当有限,但是在提供保证正确性的方法之前担心效率是一种可怕的“过早优化”形式。如果大锤内在的成本太高...... ...那么探索更便宜但仍能满足应用程序要求的替代方案是有意义的,但拒绝提供任何执行某些任务的方法,因为它“太昂贵”忽略了这一事实解决缺乏这种方法的工作可能会更加昂贵。

以上是关于我在哪里可以找到 std::launder 的真正作用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C++20 中的 std::launder 用例

为啥这里需要 std::launder ?

为啥要引入 `std::launder` 而不是让编译器处理它?

std::launder 替代 pre c++17

带有就地多态容器的 std::launder

std::launder 的效果是不是在调用它的表达式之后持续?