【问题标题】:C++ OutputIterator post-increment requirementsC++ OutputIterator 后增量要求
【发布时间】:2012-08-06 05:57:41
【问题描述】:

C++ 要求 OutputIterator 类型 X 支持 r++ 形式的表达式,其中 rX 的一个实例。这个后缀增量必须在语义上等价于:

(*){ X tmp = r; ++r; return tmp; }

并且必须返回可转换为X const& 的类型。在 C++11 中,请参阅 24.2.4(但这并不是新的)。在同一部分,它说

输出迭代器上的算法不应该尝试通过同一个迭代器两次。它们应该是单程算法。

上面给定 (*),假设我复制了返回值,例如 X a(r++);

  1. 假设 r 在递增之前可取消引用,但未取消引用。是否要求 a 可以取消引用?如果是这样,X a(r++); *a = t; 是否必须执行与 *r++ = t; 相同的分配? ar 是否有任何(其他)条件?

  2. 否则,假设r 在递增之前被取消引用/分配,并且其递增值(也)是可取消引用的。以下哪项(如果有)是明确定义的: (a) *a = t;, (b) ++a; *a = t;, (c) *r = t;?


另见后续:Dereference-assignment to a doubly incremented OutputIterator

【问题讨论】:

    标签: c++ iterator post-increment


    【解决方案1】:

    如您所述,r++ 具有操作语义

    X operator++(int) { X tmp = r; ++r; return tmp; }
    

    我已将返回值添加为 X,因为根据 24.2.2:2 Iterator 满足 CopyConstructible,因此将 r++ 的返回值复制构造为 @987654330 类型的实例是合法的@。

    接下来,*r++ = o 必须有效;这与{ const X &a(r++); *a = o; }的区别仅在于增加了一个序列点,它与上面操作语义定义中return tmp;之后的序列点合并,因此复合语句与表达式具有相同的有效性陈述。通过调用CopyConstructible{ X a(r++); *a = o; } 具有相同的有效性和操作语义。

    在这种情况下

    *r = o;
    X a(r++);
    

    以下保持:

    • (a) *a = o 无效,因为该迭代器的值已被取消引用分配;

    • (b) ++a; *a = o 无效,因为迭代器的值已经递增,违反了单遍要求,因为只有 r 的(新值)需要递增:per 24.2.4:2 的注释,输出迭代器的算法不应该 尝试通过同一个迭代器两次,尽管没有指定 通过 在此上下文中的含义;

    • (c) *r = o 是有效的,因为与 *r = o; r++; *r = o 整体的唯一区别是继续存在 r 的原始值的副本,根据 CopyConstructible 的要求没有语义影响复制的值。

    另一个有趣的问题是(对于非取消引用分配的r):

    X a(r);
    ++r;
    ++r;
    *a = o;
    

    标准并未直接涵盖这一点,但从 CopyConstructible 看来它应该是有效的。

    【讨论】:

    • 我已经询问了后续here
    • 我提出这个问题的部分动机是 multi-pass 保证 [24.2.5:3],OutputIterators 不需要提供。此保证包括(void)++X(r),*r 必须等同于*r 的条款。如上所述,r++ 是否有可能返回一个X,它在取消引用时将指向“错误”元素(因为++r 修改了tmp 也引用的某些数据结构)?或者这是不可能的,(也许)因为*r++=o 的有效性和r++ 的操作语义?
    • 实际上,鉴于我们在这里的发现:(stackoverflow.com/q/11887104/985943),我不再确定这个答案是否 100% 正确。即,缺陷 2035 (open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2035) 现在指定“在 [++r] 之后,r 不需要是可递增的,并且 r 的先前值的任何副本不再需要是可取消引用或可递增的。”所以我不清楚你可以a做什么(来自X a(r++);
    • @nknight 特别有趣的是*r++ = o : { *r = o; ++r; } 的新操作语义与r++ 的现有操作语义相结合;问题是 r++ 以前值的副本,但必须是可取消引用的;插入一个额外的副本(因为 *X(r++) = oX tmp(r++); *x = o 无法更改该要求。
    猜你喜欢
    • 2015-08-20
    • 1970-01-01
    • 2014-05-03
    • 2012-06-01
    • 2012-04-24
    • 2011-07-18
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    相关资源
    最近更新 更多