C++ 11是否允许vector <const T>?

HC4*_*ica 65 c++ const vector c++11

容器需求已从C++ 03更改为C++ 11.虽然C++ 03有一揽子要求(例如复制构造性和向量的可赋值性),但C++ 11定义了每个容器操作的细粒度要求(第23.2节).

因此,只要您只执行某些不需要赋值的操作(构造并且push_back是这样的操作),您可以例如在向量中存储可复制构造但不可赋值的类型(例如具有const成员的结构).; insert不是).

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

(让我觉得我可能错过了一些东西的部分原因是,如果你试图实例化vector<const T>,那gcc trunk会崩溃并烧掉,但是vector<T>对于T有const成员的地方来说很好).

Bo *_*son 44

不,我相信分配器要求说T可以是"非const,非参考对象类型".

对于常量对象的向量,您将无法做很多事情.const vector<T>无论如何,a 几乎是一样的.


许多年后,这个快速而肮脏的答案似乎仍然吸引着评论和投票.并不总是.:-)

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

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

T, U any type

不是任何类型实际工作.

因此,下一个标准C++ 11 在[allocator.requirements]的详细草案中说,现在表27:

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

这与我最初从记忆中写的内容非常接近.这也是问题所在.

但是,在C++ 14(草案N4296)中,表27现在说:

T, U, C any non-const object type

可能因为参考可能毕竟不是对象类型?

现在在C++ 17(草案N4659)中,表30表示:

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

因此,不仅const排除了,而且还排除了volatile.无论如何可能是旧的新闻,只是一个澄清.


另请参阅Howard Hinnant的第一手资料,目前正好在下面.

  • 一句话:我们没有设计容器来容纳const T.虽然我确实给了它一些想法.我们真的*非常接近于偶然做到这一点.据我所知,当前的关键点是默认分配器中的一对重载的`address`成员函数:当T为const时,这两个重载具有相同的签名.解决这个问题的一个简单方法是专门化`std :: allocator <const T>`并删除其中一个重载. (41认同)
  • 缓存通常是不可变对象的可变容器,并且有序向量通常是地图的替代,因此我不同意const对象的向量几乎没有用处. (7认同)
  • 这是一个耻辱.我正在使用`std :: vector <const T>`,因为它与`const std :: vector <T>`非常相似,但没有后者对持有它的类的负面影响.事实上,在我使用`vector`的大多数情况下,`std :: vector <const T>`完全是我需要的语义.现在我必须删除`const` - 以及它提供的可靠性. (7认同)
  • @ HighCommander4:我不是正面的.在libc ++上,我可以使用协作分配器构造一个向量(甚至是非空向量).我不能做任何其他事情(非常规).我不确定这是否符合你对"作品"的定义.如果我不知不觉地利用扩展,我也不会积极.为了确定,我需要在这个问题上花更多的时间.我以前做过这样的投资,但那是几年前的事,过去很多事情都发生了变化.如果确实有效,那就不是委员会的设计. (4认同)

How*_*ant 27

更新

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

底线:我们没有设计容器const T.虽然我确实给了它一些想法.我们非常接近于偶然做到这一点.据我所知,目前的症结是一对重载address默认allocator的成员函数:如果Tconst,这两个重载具有相同的签名.解决这个问题的一个简单方法是专门化 std::allocator<const T>并删除其中一个重载.

随着即将推出的C++ 17草案,在我看来,我们现在已经合法化vector<const T>,而且我也相信我们已经意外地完成了它.:-)

P0174R0消除了address过载std::allocator<T>. P0174R0没有提到支持std::allocator<const T>作为其基本原理的一部分.

更正

在下面的评论中,TC正确地指出address过载已弃用,未被删除.我的错.不推荐使用的成员不会在20.10.9中显示std::allocator,而是在其中定义,而是降级到D.9节.当我发布这个时,我忽略了扫描D章这种可能性.

谢谢你TC的纠正.我打算删除这个误导性的答案,但也许最好把这个纠正留下来,这样也许它会让别人误解我的规范.

  • 这很有趣!(现在我们只需要对它非常安静,让它在没有人注意的情况下进入C++ 17)) (6认同)
  • [分配器要求表](https://timsong-cpp.github.io/cppwp/allocator.requirements#tab:desc.var.def) 是否仍然直接禁止它?无论如何,[P0174R2](http://wg21.link/P0174R2)(这是投票通过的修订版)只会弃用,而不是删除“地址”。 (2认同)

Luc*_*iva 5

即使我们已经对此做出了很好的回答,但我还是决定做出更实际的回答,以表明可以做什么和不能做什么。

所以这不起作用:

vector<const T> vec; 
Run Code Online (Sandbox Code Playgroud)

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

vector<const shared_ptr<T>> vec;
Run Code Online (Sandbox Code Playgroud)

T不再const,而是vector持有shared_ptr,而不是T

另一方面,这确实起作用:

vector<const T *> vec;
vector<T const *> vec;  // the same as above
Run Code Online (Sandbox Code Playgroud)

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

vector<shared_ptr<const T>> vec;
Run Code Online (Sandbox Code Playgroud)

没关系

但是,如果我们将const表达式放在末尾,它现在会将指针变成一个const,因此以下内容将无法编译:

vector<T * const> vec;
Run Code Online (Sandbox Code Playgroud)

我同意,这有点令人困惑,但是您已经习惯了。


小智 5

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

vector<unique_ptr<const T>> vec;
Run Code Online (Sandbox Code Playgroud)

如果您想强制执行,则它仅vec拥有其项目的所有权。或者,如果您想要动态地将项目移入vec并在某些时候将它们移出。

正如指出的那样,指针const的语义可能会产生混淆,但shared_ptrunique_ptr没有。const unique_ptr<T>是一个常量指针,并且unique_ptr<const T>是一个常量指针,正如你所期望的。