28

所以我正在查看规范std::vector并注意到referencetypedef 从Allocator::referenceC++03 到value_type&C++11 中的更改。我很惊讶,所以我开始深入研究。

在 C++03 §20.1.5 [lib.allocator.requirements] 中有表 32,其中X::reference被定义为T&并且X::const_reference被定义为T const&

但是,在 C++11 §17.6.3.5 [allocator.requirements] 中,表 28 中缺少reference和。const_reference

接下来,我们std::allocator_traits在 C++11 中添加了 §20.6.8,其中不包括reference. 但是§20.6.9std::allocator可以。

最后,还有 §23.2.1 [container.requirements.general] 定义X::reference为“lvalue of T”和X::const_reference“const lvalue of T”。

所以,我在谷歌上搜索并发现了这篇论文(1 , 2),它建议reference从分配器要求中删除,但它没有提到它背后的任何理由。但也有一个反对改变的LWG 问题。

此外,我还找到了对 Alexander Stepanov 的采访,其中他谈到了如何reference封装特定于机器的内存布局,以及Herb Sutter 的帖子,其中他谈到了将指针指向容器元素、容器要求以及如何std::vector<bool>不是容器。

那么,您如何看待这一切?有用吗reference,有没有达到目的?“花哨”的参考文献如何符合标准?这是彻底消除它们、制定更严格的容器要求并弃用它们的大胆举措std::vector<bool>吗?

4

3 回答 3

5

因为嵌套的 typedef 是多余的。 Scott Meyers 的有效 STL,第 49 页:

该标准明确允许库实现者假设每个分配器的指针 typedef 是 T* 的同义词,并且每个分配器的引用 typedef 都与 T&

于 2013-05-03T13:33:17.337 回答
5

http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)

“它们最初的目的是使库更加灵活且独立于底层内存模型,允许程序员在库中使用自定义指针和引用类型。但是,在将 STL 纳入 C++ 标准的过程中,C++标准化委员会意识到内存模型的完全抽象会导致不可接受的性能损失。为了解决这个问题,分配器的要求变得更加严格。结果,分配器提供的定制级别比 Stepanov 最初设想的要有限。 。”

最初,它们旨在抽象出内存本身,允许一个人通过互联网连接在另一台机器上分配内存,并使用指针/引用来回复制数据以跟踪活动内容。类似地,可以用纯 C++ 制作类似 Java 的 GC。这种抽象似乎是一个了不起的想法!

然而,这招致了当时被认为是不可接受的性能损失。另外,如果你仔细想想,用代码工作几乎是不可能的。Everyvoid func(const string&)必须被制成一个template<class allocator> void func(allocator::reference),这是一个不可推导的上下文,因此您必须在函数调用 ( func<std::allocator<std::string>::const_reference>(username)) 中显式编写分配器,这是没人会做的,这会使 GC 无法正常工作。如今,分配器只是抽象内存分配/释放。

于 2014-01-09T17:29:55.780 回答
2

接受 Alexander Stepanov 采访时,他提到在将 STL 添加到标准库的提议期间,他被要求从内存模型中创建一个抽象。于是,分配器诞生了。在LWG 问题中,有一个实现示例,其中reference自定义分配器被定义为T __far&.

但是,由于我没有太多时间搜索,原因不明,C++03 标准在 §20.1.5 p4 中有以下文本:

本国际标准中描述的容器的实现允许假设其分配器模板参数满足表 32 中的以下两个附加要求。

— 给定分配器类型的所有实例都必须是可互换的,并且总是相互比较相等。

— typedef 成员 pointer、const_pointer、size_type 和 difference_type 要求分别为 T*、T const*、size_t 和 ptrdiff_t。

这有效地破坏了自定义内存模型分配器与标准容器互操作的能力。

在搜索所有提到“分配器”一词的 C++11 之前的论文期间,我发现了从标准中删除这些词的主要共识。最后,本文建议通过以下评论删除它们:

黄鼠狼的话没了。举起酒杯,敬酒。

胜利?我们终于可以疯狂地使用我们的记忆模型了吗?没有那么多。除其他事项外,同一篇论文还建议reference从分配器要求中删除。看起来它被投票加入了标准。

我之前提到的LWG 问题反对该更改,但它以以下声明结束:

没有共识做出改变

所以看起来分配器的最初目的在今天并不那么重要。这是维基百科必须说的:

分配器的当前目的是让程序员控制容器内的内存分配,而不是适应底层硬件的地址模型。事实上,修订后的标准消除了分配器表示 C++ 地址模型扩展的能力,正式(并且故意)消除了它们的原始目的。

最后,Container::reference与分配器无关。创建它是为了允许实际上不是容器的代理集合。所以它就在这里。顺便说一句,这似乎是标准中的最后一句话如何违背初衷的另一个例子。

于 2013-05-03T15:37:14.303 回答