【问题标题】:C++20 P0784R7 Non-transient allocation too brittle vs. P1004R2 constexpr std::vectorC++20 P0784R7 非瞬态分配与 P1004R2 constexpr std::vector 相比太脆弱
【发布时间】:2021-02-16 09:49:11
【问题描述】:

我想在 C++20 中创建一个广泛的 constexpr 数据存储库。数以万计的原生 C++ 对象作为“文本段”加载,即需求分页到进程中并在实例之间共享(生成代码)。

对象相互引用,需要通过各种属性进行索引、交叉引用等。所有这些都希望在编译时完成。这需要constexpr(关联)容器,但不能使用模板化(按大小、哈希大小等)容器来完成,因为一切都需要保持多态性。

首先这似乎是不可能的,因为 C++20 P0784R7 说非瞬态分配太脆弱,即不允许动态分配的内存从 constexpr 评估中泄漏出来。

同时 C++20 P1004R2 表示要支持 constexpr std::vector。在后一篇论文中,我看到了所有成员,包括标记为constexpr 的修改成员。因此,除非我遗漏了什么,否则我可以在 constexpr 评估中向 std::vectors 添加元素(编译器还不支持它,所以我无法尝试)。

// 21.3.11.5, modifiers
template<class... Args> constexpr reference emplace_back(Args&&... args);
constexpr void push_back(const T& x);
constexpr void push_back(T&& x);
...

但是为什么我不能围绕std::vector&lt;T&gt; 构建一个allocator&lt;T&gt; 并且仍然有非瞬态分配?这两个功能不是“计算等效”,即constexpr std::vector需要实现非瞬态分配,因此它也可以提供它

编译器何时最终支持它? ……或者这种可疑的矛盾甚至是延迟的原因?

【问题讨论】:

    标签: c++ stdvector constexpr c++20


    【解决方案1】:

    您对临时分配有误解。瞬态分配是在持续评估中完全存在的分配。例如:

    constexpr std::size_t summation(std::vector<unsigned int> const &vi)
    {
      std::size_t ret = 0;
      for(auto i : vi)
        ret += i;
      return ret;
    }
    
    constexpr auto sum = summation({20, 44, 98});
    
    

    summation 的调用中,最终输入源(braced-init-list 及其值)在编译时就完全知道了。是的,有一个vector,但它完全存在于常量表达式求值中。 vector 对象用于计算常量值,但vector 本身从不留下常量表达式代码。

    这种完全存在于常量评估中的分配称为“瞬态分配”。根据 C++20 的规则,此类分配是允许的。

    非瞬态分配将数据“加载为'文本段'”,这是不允许的。所以你的第一印象是正确的。

    【讨论】:

    • 目的是使用 std::vectors 作为类成员,在构造函数等中计算。
    • ... 或作为静态变量。你是说P1004R2不涵盖这个?为什么?我在哪里可以看到 en.cppreference.com/w/cpp/language/constexpr
    • @markus: "Why?" 因为它需要非瞬态分配,这是不允许的。在常量表达式上下文中创建的分配不能泄漏到非常量表达式上下文中。正如我在回答中解释的那样,这是规则。 documentation of the one allocation function that you can call at compile-time 中提到了这一点。
    • 所以总结一下(关于最初的问题)P0784R7 在 P1004R2 之上强制执行。并且在诸如 std::string 或 std::vector 之类的类型的接口声明中没有任何内容会警告您不要这样做。更具体地说,P1004R2(以及用于 std::string 的 P0980R1)或任何 constexpr(构造函数)声明的好听的 constexpr 承诺并不能保证您实际上可以为静态 constexpr 变量构造一些东西。关于我希望达到的目标,一个发人深省的事实是,我被 C 数组和 C 字符串文字困住了。
    • @markus:“... std::string 或 std::vector 的接口声明”中没有任何内容告诉您它们完全分配内存。那么为什么你会期望它的内存分配行为的这个附加属性成为它的接口的一部分呢?
    猜你喜欢
    • 2020-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多