Почему перегрузка оператора &() запрещена для классов, хранящихся в контейнерах STL?

Внезапно в эта статья ("проблема 2") Я вижу утверждение, что стандарт C++ запрещает использовать контейнеры STL для хранения элементов класса, если этот класс имеет перегруженный operator&().

Перегрузив operator&() действительно может быть проблематичным, но похоже, что оператор "address-of" по умолчанию можно легко использовать через набор грязно выглядящих приведений, которые используются в boost::addressof() и считаются переносимыми и стандартный компилятор.

Почему перегруженный operator&() запрещен для классов, хранящихся в контейнерах STL, в то время как существует обходной путь boost::addressof()?


person sharptooth    schedule 27.04.2010    source источник
comment
Из любопытства (без критики, просто из любопытства), где бы вы перегрузили оператор address-of?   -  person falstro    schedule 27.04.2010
comment
@roe: в таких классах, как ATL::CComPtr (msdn. microsoft.com/en-us/library/ezzw7k98(VS.80).aspx), что имеет смысл. Вы часто используете их вместо необработанных указателей. Вы хотите, чтобы вызовы функции типа HRESULT GetStuff( IInterface** ) выполнялись для CComPtr‹IInterface›, и для этого требуется либо метод для получения адреса инкапсулированного указателя, либо перегруженный operator&().   -  person sharptooth    schedule 27.04.2010
comment
После быстрого просмотра главы о контейнерах в стандарте я не нашел такого утверждения. Отказ от ответственности: я только что просмотрел, я мог бы пропустить это, если бы это не было выделено жирным шрифтом и / или в начале предложения :)   -  person David Rodríguez - dribeas    schedule 27.04.2010
comment
@David: требования CopyConstructible (20.1.3) указывают, что &t имеет тип T* и обозначает адрес T. Технически это не запрещает перегрузку оператора, но запрещает изменять его поведение.   -  person Mike Seymour    schedule 27.04.2010
comment
@Mike: спасибо, это то, что происходит, когда вы просто просматриваете документы :)   -  person David Rodríguez - dribeas    schedule 27.04.2010


Ответы (3)


Не глядя на ссылки, я предполагаю, что трюки в boost::addressof() были придуманы задолго до требования не перегружать унарный префикс & для объектов, которые должны храниться в контейнерах стандартной библиотеки.

Я смутно помню, как Пит Беккер (тогда работавший в Dinkumware над реализацией их стандартной библиотеки) однажды заявил, что каждый, кто перегружает оператор адреса и ожидает, что его реализация стандартной библиотеки все еще будет работать, должен быть наказан необходимостью реализации стандартной библиотеки, которая делает это.

person sbi    schedule 27.04.2010
comment
Это заставляет задаться вопросом, почему перегрузка оператора address-of вообще разрешена, не так ли? - person Joris Timmermans; 27.04.2010
comment
@MadKeithV: Когда для C++ была изобретена перегрузка операторов, нужно было решить, какие операторы должны быть перегружаемыми, а какие нет. Поскольку тогда не было никакого опыта, по крайней мере, с C++, об этом приходилось догадываться. Оглядываясь назад, легко критиковать эти догадки. (Хотя, поскольку он действительно используется, есть люди, которые утверждают, что перегрузка унарного префикса & полезна и выгодна.) - person sbi; 27.04.2010

Вероятно, потому, что проще просто запретить использование перегруженных классов operator&(), чем создать функцию std::addressof() и заменить ею каждое использование & в контейнерном коде.

person identitycrisisuk    schedule 27.04.2010
comment
Команда VS2010 все равно перерабатывала всю STL. Это не аргумент. Согласно упомянутому сообщению, это неопределенное поведение. (-1) - person xtofl; 27.04.2010
comment
Указывает ли команда VS2010 стандарт C++, я думал, что это скорее вопрос о том, почему стандарт такой, какой он есть? Другой ответ, вероятно, в любом случае лучше, что это историческая вещь. - person identitycrisisuk; 27.04.2010

Стандарт был окончательно доработан в 1998 г. с исправлениями в 2003 г., тогда как boost::addressof датируется началом 2002 года.

Более того, неясно, является ли ответ addressof. Перегрузки operator&() указывают на то, что необработанных указателей следует избегать. Член Allocator::address обеспечивает наилучший интерфейс для перехода от Allocator::reference к Allocator::pointer, поэтому в общей теории вы должны быть в состоянии эффективно ввести переопределение operator& в хорошо себя зарекомендовавший класс с помощью специального распределителя.

Учитывая, что ссылки делают почти все то же, что и указатели, а интерфейс Allocator абстрагирует все остальное, необработанные указатели не нужны.

Удобство для разработчиков библиотек не должно быть проблемой. Плохо определенная семантика Allocator::pointer является проблемой, и то, что я до сих пор читал в C++0x, не проясняет этого.

C++0x удаляет любое упоминание operator& из CopyConstructible и, кроме того, вообще не требует ничего-конструируемого для аргументов контейнера — пользователь может придерживаться emplace. Даже для vector требуется только Destructible, хотя я полагаю, что на самом деле для использования insert или erase потребуется больше.

(Обратите внимание, что в самом строгом чтении перегрузки не запрещены в C++03. Вам просто не разрешено изменять значение или тип встроенной функции.)

person Potatoswatter    schedule 27.04.2010
comment
Разработка стандарта была завершена в 1998 году в 1997 году. - person curiousguy; 02.12.2011