【问题标题】:Is storing objects of class with overloaded "operator&" in STL containers legal in C++?在 C++ 中,在 STL 容器中存储具有重载“运算符&”的类对象是否合法?
【发布时间】:2012-01-29 02:11:58
【问题描述】:

根据 C++03 标准 (23.1/3),只有 copy-constructible 类对象可以存储在 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 容器中吗?

【问题讨论】:

  • @VJovic:怎么样?重载的运算符产生对象的地址
  • @BjörnPollex 如果class Class 包含不可复制的成员变量,那么 operator& 是否重载无关紧要——它将是不可复制的。
  • @VJovic:我为此写了“假设它不违反要求”。
  • 这个问题是专门针对 C++03 的吗? C++11 去掉了容器的值类型是可复制构造的要求,也去掉了& 对可复制构造类型的要求。
  • 这个问题仍然没有意义。如果它不违反要求,那么它可以被存储。那么,你到底在问什么?

标签: c++ stl operator-overloading


【解决方案1】:

是的。在 C++03 中,& 的 CopyConstructible 要求,给定类型为 T 的值 t 和类型为 const Tu,是:

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

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

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

【讨论】:

    【解决方案2】:

    虽然在 C++03 中我们只有可以复制构造/复制分配对象,但我们获得了两个额外的、迄今为止更强大的工具来构造对象和一个额外的工具来分配对象: move 构造和 assignment 和 emplace 构造(基于完美转发)。

    多亏了这一点,该标准为容器方式的value_type 提供了更多的要求余地。例如,您可以将只能移动的unique_ptrs 存储在std::vector 中,只要您不使用任何需要CopyConstructibleCopyInsertable 的操作CopyAssignable(例如将一个容器分配给另一个)。

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

    没有要求可以用在某个value_type实例化的容器中,甚至提到address-of以任何方式操作。

    §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_type 与 A 相同,value_typeT 并给定一个 A 类型的左值 m,一个 T* 类型的指针 p ,一个 T 类型的表达式 v,以及一个 @987654339 类型的右值 rv @,定义了以下术语。 (如果 X 不能识别分配器,则下面的术语定义为好像 Astd::allocator<T>。) p>

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

    • TMoveInsertable into X 表示以下表达式格式正确: allocator_traits<A>::construct(m, p, rv);

    • TEmplaceConstructible 到 Xargs,为零或多个参数args,表示以下表达式格式正确: allocator_traits<A>::construct(m, p, args);

    序列容器表的摘录(其中p 是有效的常量迭代器,tT 类型的左值):

    a.insert(p,t)
    要求: T 应可复制插入到 X。对于 vectordequeT 也应是 CopyAssignable。
    效果:在 p 之前插入 t 的副本。

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

    【讨论】:

      猜你喜欢
      • 2012-03-08
      • 1970-01-01
      • 1970-01-01
      • 2012-01-19
      • 1970-01-01
      • 2011-02-12
      • 2012-09-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多