【问题标题】:Why is Allocator::reference being phased out?为什么 Allocator::reference 被逐步淘汰?
【发布时间】:2013-04-27 22:12:35
【问题描述】:

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

在 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,其中缺少 referenceconst_reference

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

最后,有 §23.2.1 [container.requirements.general] 将 X::reference 定义为“T 的左值”,将 X::const_reference 定义为“T 的常量左值”。

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

另外,我发现 the interview with Alexander Stepanov 在其中谈到了 reference 如何封装特定于机器的内存布局,而在 Herb Sutter's post 中他谈到了获取指向容器元素的指针、容器要求以及 std::vector<bool> 是如何做到的一个容器。

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

【问题讨论】:

  • 很好研究的问题
  • 不,它不是很大胆。如果有人尝试实例化 std::vector,我会破坏构建

标签: c++ memory-management c++11 allocator


【解决方案1】:

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

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

【讨论】:

  • 我链接到的论文实际上建议从标准中删除它。
  • 它有可能成为一个突破性的变化,所以他们可能正在缓慢地进行,从向量等中展开引用。尽管如此,我还是赞成从标准中消除任何/所有歧义。
【解决方案2】:

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

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

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

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

【讨论】:

  • 如果仍然有这个选项会很好,因为我正在对一个系统进行精确建模,当在模拟通过总线访问的模拟器上运行代码时,我想“抽象掉内存本身” .但我也希望代码使用 std 容器并且可以在我使用 std 分配器的上下文中重复使用。
  • @mattgately:迭代器仍然大部分为此工作
【解决方案3】:

the interview with Alexander Stepanov 中,他提到在向标准库添加 STL 的提议期间,他被要求从内存模型中创建一个抽象。于是,分配器诞生了。在LWG issue 中有一个实现示例,其中自定义分配器的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 之前的论文期间,我发现了从标准中删除这些词的主要共识。最后,this paper 建议删除它们,并附上以下评论:

黄鼠狼的话不见了。举杯敬酒。

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

我之前提到的LWG issue 反对更改,但它被以下声明关闭:

没有一致同意做出改变

所以看起来分配器的最初目的在今天并不那么重要。这是Wikipedia 不得不说的:

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

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

【讨论】:

  • “原因不明”但列在维基百科页面的第二段...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-23
  • 1970-01-01
相关资源
最近更新 更多