表达式E是核心常量表达式,除非E的计算遵循抽象机器(intro.execution)的规则,将计算下列之一:
布局-新表达式不是常量表达式。
为了解决这个问题,C++20添加了std::construct_at。那么,为什么一个新的位置表达式不能成为一个常量表达式呢?
发布于 2022-10-12 01:58:51
因此,我在不久前的这里上启动了一条推特帖子来回答这个问题:
当前的实现不允许将
new()放置在constexpr上下文中。
我回答说:
如果我们看看p0784r0:https://wg21.link/p0784r0 该文件提到了两种方法:
当我们到达p0784r3:https://wg21.link/p0784r3时
安置新的是删除,IIUC有执行问题在这里。
理查德·史密斯的回复
对于某些实现来说,完全布局新的支持是很困难的,因此通过std::construct_at和allocator_traits::construct公开了一个受限的表单。现在,在clang中,我们实际上实现了一种相当通用的新布局形式,但只允许它在命名空间std中使用。
我问:
我很好奇为什么对于某些实现来说这很困难,或者为什么对clang来说并不困难。
对此,回复是:
我被告知,从
void*参数获得新的返回到类型化指针对于某些constexpr评估器来说是不可行的,这可能是因为它们如何表示指针。construct_at避免了这一点,因为它需要一个T*而不是void*。
基本上,它归结为一些实现--没有适当的机制--使用新的布局,以一种一般的方式来完成这一任务。这个文档对此进行了一些讨论,但确实提出了更多的问题,然后回答了问题,但也暗示了一些细节:
不幸的是,这允许放置新的污点分析,这些分析使用地址值传播来根据指针指向的位置来细化混叠。在上面的例子中,这样的优化可能会发现bp->buf的地址将与对象a相关联。然后,优化器可以从该发现中决定,对内存的访问应该通过一个极值来完成,这个极值可以在不调用未定义行为的情况下访问a的存储值(§3.10 basic.lval)。通过新表达式进行的初始化不是这样的访问。
发布于 2022-10-08 09:55:44
发布于 2022-10-14 00:09:58
放置-新表达式不是常量表达式,因为如果它们创建的对象没有被正确销毁,它们会调用未定义的行为。这是因为放置-新表达式绕过了正常的对象构造/破坏机制,而程序员则负责手动调用析构函数。如果要在常量表达式中创建对象,可以使用std::construct_at在给定地址初始化对象:
int main(int argc, char* argv[]) {
constexpr auto foo = []() {
auto buffer = std::array<int, 4>{};
return std::construct_at(buffer.data(), 1);
};
static_assert(foo() == 1, "!");
}https://stackoverflow.com/questions/73843218
复制相似问题