【问题标题】:Does C++11 allow vector<const T>?C++11 是否允许 vector<const T>?
【发布时间】:2020-08-06 17:56:13
【问题描述】:

容器要求已从 C++03 更改为 C++11。虽然 C++03 有全面的要求(例如,向量的复制可构造性和可分配性),但 C++11 对每个容器操作定义了细粒度的要求(第 23.2 节)。

因此,您可以例如只要您只执行某些不需要赋值的操作(构造和push_back 就是这样的操作;insert不是)。

我想知道的是:这是否意味着标准现在允许vector&lt;const T&gt;?我看不出有任何不应该的理由 - const T,就像具有 const 成员的结构一样,是一种可复制构造但不可分配的类型 - 但我可能错过了一些东西。

(让我觉得我可能遗漏了什么的部分原因是,如果您尝试实例化 vector&lt;const T&gt;,gcc 主干会崩溃并烧毁,但 vector&lt;T&gt; 可以在其中 T 有一个 const 成员)。

【问题讨论】:

    标签: c++ vector c++11 constants


    【解决方案1】:

    不,我相信分配器要求说 T 可以是“非常量、非引用对象类型”。

    你不能用常量对象的向量做很多事情。无论如何,const vector&lt;T&gt; 几乎是一样的。


    多年后,这个快速而肮脏的答案似乎仍然吸引着 cmets 和投票。并不总是向上。 :-)

    所以要添加一些适当的参考:

    对于我在纸上的 C++03 标准,[lib.allocator.requirements] 部分中的表 31 说:

    T, U any type

    并不是说 any 类型确实有效。

    因此,下一个标准 C++11 在 [allocator.requirements] 和现在的表 27 中显示 in a close draft

    T, U, C any non-const, non-reference object type

    这与我最初凭记忆在上面写的非常接近。这也是问题所在。

    但是,在 C++14 (draft N4296) 中,表 27 现在显示:

    T, U, C any non-const object type

    可能是因为引用毕竟不是对象类型?

    现在在 C++17 (draft N4659) 中,表 30 显示:

    T, U, C any cv-unqualified object type (6.9)

    因此,不仅排除了const,还排除了volatile。无论如何可能是旧消息,只是一个澄清。


    另请参阅Howard Hinnant's first-hand info,目前就在下方。

    【讨论】:

    • 底线:我们没有设计容器来容纳 const T。虽然我确实考虑过。而我们真的接近于意外地做到这一点。据我所知,当前的症结在于默认分配器中的一对重载address 成员函数:当 T 为 const 时,这两个重载具有相同的签名。纠正此问题的一种简单方法是专门化 std::allocator&lt;const T&gt; 并删除其中一个重载。
    • @HighCommander4:我不积极。在 libc++ 上,我可以使用协作分配器构造一个向量(甚至是非空向量)。我不能用它做任何其他事情(非常量)。我不确定这是否符合您对“作品”的定义。如果我无意中利用了延期,我也不积极。为了确定,我需要在这个问题上投入更多的时间。我之前已经及时进行过这样的投资,但那是几年前的事了,在此期间很多事情都发生了变化。如果它确实有效,那么它不是委员会的设计。
    • @Howard:我想不出任何技术障碍可以做到push_back。但如果设计不允许,我们最好不要这样做。我只是好奇。
    • 缓存通常是不可变对象的可变容器,排序向量通常是映射的替代品,所以我不同意 const 对象的向量没有什么用处。
    • 很遗憾。我使用std::vector&lt;const T&gt; 正是因为它与const std::vector&lt;T&gt; 非常相似,但没有后者对持有它的类的负面影响。事实上,std::vector&lt;const T&gt; 正是我在使用vector 的大多数情况下在语义上所需要的。现在我必须放弃const - 以及它提供的可靠性。
    【解决方案2】:

    更新

    根据我在 2011 年评论的接受(和正确)答案:

    底线:我们没有设计容器来容纳const T。虽然我做了 考虑一下。我们非常接近做到这一点 意外。据我所知,目前的症结是 默认中的一对重载的address 成员函数 分配器:当Tconst时,这两个重载有相同的 签名。纠正这个问题的一个简单方法是专门化 std::allocator&lt;const T&gt; 并删除其中一个重载。

    随着即将发布的 C++17 草案,在我看来,我们现在已经将 vector&lt;const T&gt; 合法化,而且我也相信我们已经做到了不小心。 :-)

    P0174R0std::allocator&lt;T&gt; 中删除address 重载。 P0174R0 没有提及支持 std::allocator&lt;const T&gt; 作为其基本原理的一部分。

    更正

    在 T.C. 下面的 cmets 中。正确地指出address 重载已弃用,而不是删除。我的错。已弃用的成员不会出现在定义 std::allocator 的 20.10.9 中,而是降级到 D.9 节。当我发布此内容时,我忽略了扫描 D 章是否存在这种可能性。

    谢谢 T.C.进行更正。我考虑删除这个误导性的答案,但也许最好保留这个更正,这样可能会防止其他人像我一样误读规范。

    【讨论】:

    • 这很有趣! (现在我们只需要对它保持安静,让它溜进 C++17 没有任何人注意到 :))
    • the allocator requirements table 不还是直接禁止吗?无论如何,P0174R2(这是投票的修订版)只会弃用,而不是删除address
    • @T.C.:你说得对。谢谢指正。
    • 所以 c++2x 最终将允许 vector&lt;const T&gt; :)
    • 答案“底线:我们没有设计容器来容纳 const T。”假设目标是容器应该容纳“const T”。然而,有人可能会争辩说,用户的目标是限制容器上的操作——例如'back()' 返回 "const T&" - 无论容器包含什么。
    【解决方案3】:

    尽管我们对此已经有了很好的答案,但我还是决定提供一个更实际的答案来说明什么可以做,什么不能做。

    所以这不起作用:

    vector<const T> vec; 
    

    只需阅读其他答案即可了解原因。而且,正如您可能已经猜到的那样,这也不起作用:

    vector<const shared_ptr<T>> vec;
    

    T 不再是const,但vector 持有shared_ptrs,而不是Ts。

    另一方面,这确实工作:

    vector<const T *> vec;
    vector<T const *> vec;  // the same as above
    

    但是在这种情况下, const 是被指向的对象,而不是指针本身(这是向量存储的内容)。这相当于:

    vector<shared_ptr<const T>> vec;
    

    这很好。

    但是如果我们将const 放在表达式的末尾,它现在会将指针变成const,所以下面的代码不会编译:

    vector<T * const> vec;
    

    有点混乱,我同意,但你习惯了。

    【讨论】:

      【解决方案4】:

      补充其他答案,另一种方法是使用:

      vector<unique_ptr<const T>> vec;
      

      如果您想强制只有vec 拥有其项目的所有权。或者,如果您想要动态地将项目移动到 vec 并在某个时候将它们移出。

      正如所指出的,指针 const 语义可能会令人困惑,但 shared_ptrunique_ptr 不会。 const unique_ptr&lt;T&gt; 是一个常量指针,unique_ptr&lt;const T&gt; 是一个常量指针,正如你所期望的。

      【讨论】:

        【解决方案5】:

        据我所知,如果您希望向量中的每个 T 元素都是 const,请改用 const vector。因为如果您的向量是 const 限定的,则只能调用不会修改任何 T 元素的 const 限定方法。

        【讨论】:

        • 这将不允许从向量中添加、删除或重新排序元素。
        • 当然,vector 的添加、删除、重新排序方法是非 const 限定的。我真正的意思是,如果你想将元素视为 const,只需使向量 const 限定就足够了。
        • 我的意思是这样做的方式更多,限制性更强。
        • @bolov 好的,非常感谢。
        猜你喜欢
        • 2017-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        相关资源
        最近更新 更多