为什么不能在STL容器中存储的类中重载operator&()运算符?

7

突然在这篇文章("问题2")中,我看到了一句话,即C++标准禁止使用STL容器存储类的元素,如果该类有重载的operator&()

虽然重载operator&()确实可能会有问题,但似乎可以通过一组在boost::addressof()中使用的肮脏的转换来轻松使用默认的“取地址”操作符,并且被认为是可移植和标准兼容的。

为什么对于存储在STL容器中的类而言,具有重载operator&()是被禁止的,而boost::addressof()的解决方法存在呢?


出于好奇(没有批评,真的只是好奇),您在哪里会重载取地址运算符? - falstro
1
@roe:在像ATL::CComPtr这样的类中(http://msdn.microsoft.com/en-us/library/ezzw7k98(VS.80).aspx),这是有意义的。你经常使用它们来代替原始指针。你希望像 HRESULT GetStuff(IInterface**) 这样的函数调用可以用于 CComPtr<IInterface>,这需要有一种方法来检索封装指针的地址或重载 operator&() - sharptooth
1
在标准中浏览了一下容器章节后,我没有发现这样的声明。免责声明:我只是简单地浏览了一下,如果它不是用粗体字和/或出现在句子开头,我可能会错过它 :) - David Rodríguez - dribeas
4
CopyConstructible的要求(20.1.3)规定&t的类型为T*,且“表示T的地址”。这在技术上并不禁止重载运算符,但是禁止改变其行为。 - Mike Seymour
@Mike:谢谢,这就是你只是浏览文档时会发生的事情 :) - David Rodríguez - dribeas
3个回答

6

没有查看链接,我猜测 boost::addressof() 中的技巧是在不重载一元前缀 & 的要求之后发明出来的,以便容纳 std lib 容器中的对象。

我模糊地记得 Pete Becker(当时在 Dinkumware 上为他们的标准库实现工作)曾经说过,每个重载地址运算符并希望他们的标准库实现仍然正常工作的人都应该被惩罚,让他们实现一个可以这样做的标准库。


这确实让人想知道为什么首先允许重载取地址运算符,不是吗? - Joris Timmermans
3
当 C++ 中发明运算符重载时,需要决定哪些运算符应该可以重载,哪些不应该。由于那时还没有经验 - 至少对于 C++ 而言是如此 - 必须进行猜测。回想起来很容易批评这些猜测。(尽管它确实被使用,有人会认为重载单目前缀'&' 是有用和有益的。) - sbi

2

可能是因为禁止使用重载运算符&()类比创建std::addressof()函数并用它替换容器代码中的每个&使用起来更轻松。


VS2010团队正在重新制作整个STL。这不是一个争论点。根据所提到的帖子,这是未定义的行为。(-1) - xtofl
1
VS2010团队是否指定了C++标准?我认为这更多是一个关于标准为什么是这样的问题。另一个答案可能更好,即这是一个历史性的事情。 - identitycrisisuk

1

该标准于1998年完成,2003年进行了修正,而boost::addressof可以追溯到2002年初。

此外,不清楚addressof是否是答案。 operator&()的重载表明应避免使用原始指针。 Allocator::address成员提供了从Allocator::referenceAllocator::pointer的最佳接口,因此在一般理论中,您应该能够有效地通过自定义分配器引入一个operator&覆盖到一个行为良好的类中。

考虑到引用几乎可以执行指针所做的所有操作,而分配器接口抽象了其他所有内容,因此不需要使用原始指针。

方便库实现者不应成为问题。 Allocator::pointer的语义不明确是一个问题,我在C++0x中所读到的并没有解决这个问题。

C++0x从CopyConstructible中删除了对operator&的任何提及,而且完全不需要对容器参数进行任何构造 - 用户可以使用emplace。即使是vector也只需要Destructible,尽管我认为实际使用inserterase需要更多。

(请注意,在最严格的解读中,C++03中并没有禁止重载。你只是不能改变内置类型的值或类型。)


标准于1998年最终确定。 - curiousguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接