【问题标题】:STL-Like range, What could go wrong if I did this?类似 STL 的范围,如果我这样做会出什么问题?
【发布时间】:2010-01-31 09:08:03
【问题描述】:

我正在编写(作为自学练习)一个简单的类似 STL 的范围。它是一个不可变随机访问的“容器”。我的范围,只保留它的起始元素,元素的数量和步长(两个连续元素之间的差异):

struct range
{
...
private:
  value_type m_first_element, m_element_count, m_step;
};

因为我的范围不包含元素,所以它使用以下方法计算所需的元素:

// In the standards, the operator[]
// should return a const reference.
// Because Range doesn't store its elements
// internally, we return a copy of the value.
value_type operator[](size_type index)
{
    return m_first_element + m_step*index;
}

如您所见,我没有像标准所说的那样返回const reference。现在,我可以假设 const reference 和元素的副本在使用标准库中的非变异算法方面是相同的吗?

非常感谢任何有关该主题的建议。


@Steve Jessop:你提到了迭代器。

其实我用的是sgi as my reference。在该页面的末尾,它说:

假设 x 和 y 是同一范围内的迭代器:

不变量身份
x == y if and only if &*x == &*y

所以,它归结为我实际上问过的同一个原始问题:)

【问题讨论】:

  • 如果您在 operator[] 中创建了一个要返回的元素,然后返回了一个对它的引用,那么该引用是否总是一个错误的引用,因为该实例会立即超出范围?
    该标准讨论了 CONTAINERS 中的引用,这不是容器。
  • @Chris 我同意它不是一个真正的容器。这就是为什么我在上面的第二句话中将“容器”放在双引号之间。
  • 您可能需要查看 boost::iterator_range 和 boost::sub_range 以获得灵感:boost.org/doc/libs/1_41_0/libs/range/index.html
  • 您可以同时拥有“范围”对象和迭代器。我也认为您过于担心:如果您的迭代器不具有这种恒等式,那就这样吧。如果按值返回,那么无论如何都可能取不到结果的地址。

标签: c++ stl standards


【解决方案1】:

标准算法并没有真正使用operator[],它们都是根据迭代器定义的,除非我忘记了一些重要的东西。是否计划在 operator[] 之上为您的“范围”而不是迭代器重新实现标准算法?

在非变异算法确实使用迭代器的情况下,它们都是根据*it 定义的,可分配给任何需要分配的对象,或者对某些指定的操作或函数调用有效。我认为所有或大多数此类操作都具有价值。

我能想到的一件事是,您不能在需要非常量引用的地方传递值。是否有任何需要非常量引用的非变异算法?可能不会,前提是任何函子参数等都有足够的const

很抱歉,我不能肯定地说没有奇怪的弯道出了问题,但对我来说这听起来基本没问题。即使有任何小问题,您也可以通过您的算法版本和标准版本之间的要求非常细微的差异来修复它们。

编辑:可能出错的第二件事是获取指针/引用并将它们保持太长。据我所知,标准算法不保留指针或元素引用——原因是 containers 保证了指向元素的指针的有效性,迭代器类型只告诉你什么时候iterator 保持有效(例如,当原始迭代器递增时,输入迭代器的副本不一定保持有效,而前向迭代器可以以这种方式复制用于多遍算法)。由于算法看不到容器,只有迭代器,所以我没有理由认为这些元素是持久的。

【讨论】:

    【解决方案2】:

    STL 容器中的项目预计会一直被复制;例如,考虑何时必须重新分配向量。所以,你的例子很好,除了它只适用于随机迭代器。但我怀疑后者可能是设计使然。 :-P

    【讨论】:

      【解决方案3】:

      您希望您的范围可用于 STL 算法吗?使用第一个和最后一个元素不是更好吗? (考虑到经常需要/使用end() 的事实,您必须预先计算它的性能。)或者,您是否指望连续元素(这是我的第二点)?

      【讨论】:

      • end() 可以很简单地计算出来:m_first_element + m_step*m_element_count,所以真的不成问题。我写了所有需要使range 成为 Immutable 随机访问容器的东西,除了我在问题中所说的:)
      • 这是我问题的第二部分:是否可以将此标准强加于容器的内存管理部分?
      • 对不起,我没明白你在说什么,你能详细说明一下吗:)
      【解决方案4】:

      由于您将“容器”放在“引号”中,因此您可以做任何您想做的事情。

      STL 类型的事物(迭代器、容器上的各种成员函数..)返回引用,因为引用是左值,并且某些构造(即 myvec[i] = otherthing)可以编译。想想 std::map 上的 operator[]。对于 const 引用,我想这不仅仅是避免复制的值。

      不过,在方便的时候,这条规则总是被违反。让迭代器类将当前值存储在成员变量中也很常见,纯粹是为了返回一个引用或 const 引用(是的,如果迭代器是高级的,这个引用将是无效的)。

      如果您对这类东西感兴趣,您应该查看 boost 迭代器库。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多