Законно ли хранение объектов класса с перегруженным оператором & в контейнерах STL в C ++? - PullRequest
6 голосов
/ 28 декабря 2011

Согласно стандарту C ++ 03 (23.1 / 3) в контейнерах STL могут храниться только объекты класса копирования . Конструктор копирования описан в 20.1.3 и требует, чтобы "&" выдает адрес объекта.

Теперь предположим, что у меня есть этот класс:

class Class {
public:
   Class* operator&()
   {
       //do some logging
       return this;
   }
   const Class* operator&() const
   {
       //do some logging
       return this;
   }
   //whatever else - assume it doesn't violate requierements
};

Можетобъекты этого класса легально хранятся в контейнерах STL?

Ответы [ 2 ]

5 голосов
/ 28 декабря 2011

Да. В C ++ 03 требования CopyConstructible для &, для заданных значений t типа T и u типа const T, составляют:

  • &t имеет тип T* и дает адрес t и
  • &u имеет тип const T* и дает адрес u.

Ваши перегруженные операторы имеют такое поведение; поэтому, если класс удовлетворяет другим требованиям CopyConstructible и Assignable, значения этого типа могут храниться в любом контейнере C ++ 03.

C ++ 11 ослабляет эти требования, требуя, чтобы типы были перемещаемыми или копируемыми только в контейнерах или операциях, которые конкретно имеют такие требования, и удаляя довольно странную спецификацию того, что & должен делать; так что с вашим классом все в порядке, опять-таки при условии, что он отвечает всем другим требованиям для конкретного контейнера и набора операций, которые вы используете.

1 голос
/ 28 декабря 2011

В то время как в C ++ 03 у нас только была возможность копировать объекты построения / копирования, мы получили два дополнительных, гораздо более мощных инструмента для создания объектов и один дополнительный инструмент для назначения объектов: перемещениеКонструкция, назначение и использование конструкции (на основе идеальной переадресации).

Благодаря этому стандарт дает value_type возможности для контейнеров в своих требованиях.Например, вам разрешено хранить unique_ptr s, которые предназначены только для перемещения, в std::vector, если вы не используете никаких операций, требующих CopyConstructible , CopyInsertable или CopyAssignable (например, присвоение одного контейнера другому).

Могут ли объекты этого класса легально храниться в контейнерах STL?

Да , нет требований о том, что может использоваться в контейнере, для которого создан определенный value_type, даже упоминающий оператор адреса в любом случае.

§17.6.3.1 [utility.arg.requirements]

Определения шаблонов в стандартной библиотеке C ++ относятся к различным именованным требованиям, подробности которых приведены в таблицах 17–24.

(Таблицы 17 и 18 - Сопоставимые требования)

Table 19 — DefaultConstructible requirements [defaultconstructible]
Expression               Post-condition
T t;                     object t is default-initialized
T u{};                   object u is value-initialized
T()                      a temporary object of type T is value-initialized
T{}

Table 20 — MoveConstructible requirements [moveconstructible]
Expression               Post-condition
T u = rv;                u is equivalent to the value of rv before the construction
T(rv)                    T(rv) is equivalent to the value of rv before the construction
rv’s state is unspecified

Table 21 — CopyConstructible requirements (in addition to MoveConstructible) [copyconstructible]
Expression               Post-condition
T u = v;                 the value of v is unchanged and is equivalent to u
T(v)                     the value of v is unchanged and is equivalent to T(v)

Table 22 — MoveAssignable requirements [moveassignable]
Expression    Return type    Return value    Post-condition
t = rv        T&             t               t is equivalent to the value of
                                             rv before the assignment
rv’s state is unspecified.

Table 23 — CopyAssignable requirements(in addition to MoveAssignable) [copyassignable]
Expression    Return type    Return value    Post-condition
t = v         T&             t               t is equivalent to v, the value of
                                             v is unchanged

Table 24 — Destructible requirements [destructible]
Expression               Post-condition
u.~T()                   All resources owned by u are reclaimed, no exception is propagated.

Затем мы также получили требования к контейнерам.Они основаны на их типах распределителя:

§23.2.1 [container.requirements.general] p13

Все контейнеры, определенные в этом разделе и в (21.4), за исключением массива, отвечают дополнительным требованиям, связанным с распределителемконтейнер, как описано в Таблице 99. Для данного типа контейнера X с типом allocator, идентичным A и value_type, идентичным T и дано значение l m типа A, указатель p типа T*, выражение v типа T и значение rv типа T, определены следующие термины.(Если X не учитывает распределителя, приведенные ниже термины определяются следующим образом: A были std::allocator<T>.)

  • T is CopyInsertable в X означает, что следующее выражение правильно сформировано: allocator_traits<A>::construct(m, p, v);

  • T is MoveInsertable в X означает, что следующее выражение правильно сформировано: allocator_traits<A>::construct(m, p, rv);

  • T is EmplaceConstructible в X с args, дляноль или более аргументов args, означает, что следующее выражение правильно сформировано: allocator_traits<A>::construct(m, p, args);

Выдержка из таблицы для контейнеров последовательности(где p является действительным константным итератором, а t является lvalue типа T):

a.insert(p,t)
Требуется: T должен быть CopyInsertable в X.Для vector и deque, T также должны иметь значение CopyAssignable.
Эффекты: Вставляет копиюt до p.

Если вы никогда не используете этот конкретный вариант insert (и другие члены, для которых требуется CopyInsertible), ваш тип не обязательно должен быть CopyInsertable.Легко как то.То же самое касается всех остальных участников.Требование только о том, что должно быть выполнено , является требованием уничтожения (логично, не правда ли?).

...