根据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
类型的t
和const 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,只要不使用任何需要CopyConstructible、CopyInsertable或CopyAssignable的操作(例如将一个容器分配给另一个容器)。
这个类对象可以合法存储在STL容器中吗?
Yes, none可以在特定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 intoX
表示以下表达式格式良好:allocator_traits<A>::construct(m, p, v);
T
is MoveInsertable intoX
表示以下表达式格式良好:allocator_traits<A>::construct(m, p, rv);
T
is EmplaceConstructible intoX
fromargs
,对于0个或多个参数args
,表示以下表达式格式良好:allocator_traits<A>::construct(m, p, args);
摘自序列容器的表(p
是有效的const迭代器,t
是T
类型的左值):
a.insert(p,t)
要求:T
应CopyInsertable intoX
。对于vector
和deque
,T
也是可CopyAssignable的。
效果:在p之前插入t的副本。
如果您从不使用特定的insert
变体(以及其他需要copyinserable的成员),则您的类型不需要是CopyInsertable。就这么简单。其他成员也一样。必须满足的惟一要求是可破坏的要求(合乎逻辑,不是吗?)