首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么位置-新表达式不能是一个常量表达式?

为什么位置-新表达式不能是一个常量表达式?
EN

Stack Overflow用户
提问于 2022-09-25 08:56:51
回答 3查看 389关注 0票数 15

根据[expr.const]/5.18

表达式E是核心常量表达式,除非E的计算遵循抽象机器(intro.execution)的规则,将计算下列之一:

  • 一个新的表达式(expr.new),除非所选的分配函数是一个可替换的全局分配函数(new.delete.single,new.delete.array),并且所分配的存储被解除在E的计算范围内;

布局-新表达式不是常量表达式。

为了解决这个问题,C++20添加了std::construct_at。那么,为什么一个新的位置表达式不能成为一个常量表达式呢?

EN

回答 3

Stack Overflow用户

发布于 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)。通过新表达式进行的初始化不是这样的访问。

票数 11
EN

Stack Overflow用户

发布于 2022-10-08 09:55:44

它遵循从…

在计算常量表达式时,总是省略对分配函数的调用。只有新的表达式,否则会导致对的调用,一个可替换的全局分配函数,才能在常量表达式中计算。

简而言之,安置新在这里没有资格(提示:由于没有使用可替换分配函数)。

票数 -1
EN

Stack Overflow用户

发布于 2022-10-14 00:09:58

放置-新表达式不是常量表达式,因为如果它们创建的对象没有被正确销毁,它们会调用未定义的行为。这是因为放置-新表达式绕过了正常的对象构造/破坏机制,而程序员则负责手动调用析构函数。如果要在常量表达式中创建对象,可以使用std::construct_at在给定地址初始化对象:

代码语言:javascript
复制
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, "!");
}
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73843218

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档