在 STL 容器中存储具有重载"operator&"的类对象在 C++ 中合法吗?



根据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容器中吗?

是。在c++ 03中,给定T类型的tconst T类型的u值时,&的CopyConstructible要求为:

  • &t类型为T*,并给出t的地址,
  • &u的类型为const T*,并给出u的地址。

你的重载操作符有这种行为;因此,假设该类满足其他CopyConstructible和Assignable要求,则该类型的值可以存储在任何c++ 03容器中。

c++ 11放宽了这些要求,要求类型只能在有这种要求的容器或操作中可移动或可复制,并删除了&必须做的相当奇怪的规范;因此,您的类仍然很好,假设它满足您使用的特定容器和操作集的所有其他要求。

虽然在c++ 03中,我们只有可以复制构造/复制赋值对象,但我们有两个额外的,迄今为止更强大的工具来构造对象和一个额外的工具来赋值对象:移动构造和赋值和放置构造(基于完全转发)。

由于这一点,该标准给了容器的value_type更大的要求余地。例如,允许在std::vector中存储只能移动的unique_ptr s,只要不使用任何需要CopyConstructibleCopyInsertableCopyAssignable的操作(例如将一个容器分配给另一个容器)。

这个类对象可以合法存储在STL容器中吗?

Yesnone可以在特定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

除array外,本节和(21.4)中定义的所有容器都满足分配器感知容器的附加要求,如表99所示。给定容器类型 X 具有与 A 相同的allocator_type和与 T 相同的 value_type 、类型为 A 的左值 m 、类型为 T* 的指针 p 、类型为 T 的表达式 v 和类型为 T 的右值 rv ,定义了下列术语。(如果 X 不是分配器感知的,下面的术语定义为如果 A std::allocator<T> )

  • T is CopyInsertable into X 表示以下表达式格式良好:allocator_traits<A>::construct(m, p, v);

  • T is MoveInsertable into X 表示以下表达式格式良好:allocator_traits<A>::construct(m, p, rv);

  • T is EmplaceConstructible into X from args ,对于0个或多个参数 args ,表示以下表达式格式良好:allocator_traits<A>::construct(m, p, args);

摘自序列容器的表(p是有效的const迭代器,tT类型的左值):

a.insert(p,t)
要求: T 应CopyInsertable into X 。对于 vector deque T 也是可CopyAssignable的。
效果:在p之前插入t的副本。

如果您从不使用特定的insert变体(以及其他需要copyinserable的成员),则您的类型不需要是CopyInsertable。就这么简单。其他成员也一样。必须满足的惟一要求是可破坏的要求(合乎逻辑,不是吗?)

最新更新