为什么placement-new表达式不能是常量表达式?

Bla*_*ger 15 c++ placement-new constant-expression c++20

根据[expr.const]/5.18

表达式 E 是核心常量表达式,除非对 E 的求值遵循抽象机 ([intro.execution]) 的规则,将求值以下其中一项:

  • new 表达式 ([expr.new]),除非所选分配函数是可替换的全局分配函数 ([new.delete.single]、[new.delete.array]),并且分配的存储空间在E;

放置新表达式不是常量表达式。

为了解决这个问题,C++20 添加了std::construct_at. 那么为什么不能将placement-new表达式设为常量表达式呢?

Sha*_*our 13

所以我不久前在 Twitter 上发布了一个帖子回答这个问题:

\n
\n

当前的实现不允许放置new()在 constexpr 上下文中。

\n
\n

我回答说:

\n
\n

如果我们看一下 p0784r0:https://wg21.link/p0784r0

\n

该论文提到了两种方法:

\n
    \n
  • 就安置而言 新
  • \n
  • 就标准分配器而言
  • \n
\n

当我们到达 p0784r3 时: https: //wg21.link/p0784r3

\n

新的安置被放弃,IIUC 这里存在实施问题。

\n
\n

理查德·史密斯的答复

\n
\n

对于某些实现来说,完全放置新的支持是困难的,因此通过 std::construct_at 和 allocator_traits::construct 公开了受限形式。现在在 clang 中,我们实际上实现了一种相当通用的放置 new 的形式,但只允许它在命名空间 std 内。

\n
\n

我问:

\n
\n

我很好奇为什么这对于某些实现来说很困难,或者为什么这对于 clang 来说并不困难可能更容易。

\n
\n

对此的答复是:

\n
\n

有人告诉我,void*对于某些评估者来说,从参数到放置 new 回到类型化指针是不可行的constexpr,大概是由于它们表示指针的方式。construct_at避免了这种情况,因为它需要 a 而T*不是 a void*

\n
\n

基本上,这归结为某些实现没有适当的机制来使用新的放置以通用方式执行此操作。本文档对此进行了一些讨论,但确实提出了更多问题,然后给出了答案,但暗示了一些细节:

\n
\n

不幸的是,这使得新的放置可能会导致错误的分析,这些分析使用地址值传播来基于了解指针指向的位置来优化别名。在上面的例子中,这样的优化可能会发现bp->buf[0]的地址与对象a相关联。根据该发现,优化器可能会决定对内存的访问应该通过泛左值来完成,该泛左值可以访问 a 的存储值而不调用未定义的行为(\xc2\xa73.10 [basic.lval])。通过 new 表达式完成的初始化不是这样的访问。

\n
\n

  • @ShafikYaghmour:你不能“@”尚未参与的人(使用非唯一名称等)。 (3认同)

dar*_*une -2

来自

在计算常量表达式期间,始终会省略对分配函数的调用。只有那些会导致调用可替换全局分配函数的new 表达式才能在常量表达式中求值。

简而言之,placement new在这里不符合条件(提示:由于没有使用可替换的分配函数)。