不可变的C ++容器类

时间:2011-03-29 21:00:36

标签: c++ stl

假设我有一个C ++类Container,它包含一些Element类型的元素。由于各种原因,在构造之后修改或替换内容是低效的,不合需要的,不必要的,不切实际的和/或不可能的(1)。类似于const std::list<const Element>(2)的行。

Container可以满足STL的“容器”和“序列”概念的许多要求。它可以提供各种类型,例如value_typereference等。它可以提供默认构造函数,复制构造函数,const_iterator类型,begin() const,{{1} },end() constsize,所有比较运算符,可能还有一些emptyrbegin() constrend() constfront(),{{1 }和back()

但是,operator[]()无法提供at()Containerinserteraseclear,非常量{{1具有预期语义的非常量push_front,非常量push_back或非常量front。因此back似乎不能作为“序列”。此外,operator[]无法提供atContainer,并且无法提供指向非const元素的Container类型。因此,它甚至不能成为“容器”。

operator=会遇到一些功能较弱的STL概念吗?是否有“只读容器”或“不可变容器”?

如果swap不符合任何规定的一致性水平,那么部分一致性是否有价值?当它没有资格时,是否会误导它看起来像一个“容器”?是否有一种简洁,明确的方式可以记录一致性,这样我就不必明确记录符合要求的语义?同样,一种记录它的方法,以便未来的用户知道他们可以利用只读的通用代码,但是不要指望变异算法有效吗?

如果我放松了这个问题,iterator是可分配的(但它的元素不是),我会得到什么?此时,ContainerContainer是可能的,但取消引用Container仍会返回operator=swap现在是否有资格成为“容器”?

iteratorconst Element的界面大致相同。这是否意味着它既不是“容器”也不是“序列”?

脚注(1)我有覆盖整个频谱的用例。我有一个容器类可以调整一些只读数据,所以它必须是不可变的。我有一个容器,可以根据需要生成自己的内容,所以它是可变的,但你不能像STL所要求的那样替换元素。我还有另一个容器,它以一种使Container如此慢以至于永远无用的方式存储其元素。最后,我有一个字符串,以UTF-8存储文本,同时公开面向代码点的接口;可变的实现是可能的,但完全没有必要。

脚注(2)这只是为了说明。我很确定const std::list<T>需要一个可赋值的元素类型。

2 个答案:

答案 0 :(得分:2)

STL没有定义任何较小的概念;主要是因为const的概念通常表示在每个迭代器或每个引用级别上,而不是在每个类级别上。

您不应该为iterator提供意外的语义,只提供const_iterator。这允许客户端代码在出错时在最合理的位置(具有最易读的错误消息)失败。

最简单的方法可能是封装它并防止所有非const别名。

class example {
    std::list<sometype> stuff;
public:
    void Process(...) { ... }
    const std::list<sometype>& Results() { return stuff; }
};

现在任何客户端代码都知道他们可以使用需要变异的Results- nada的返回值做什么。

答案 1 :(得分:1)

只要您的对象可以提供符合条件的const_iterator,它就不必拥有任何其他东西。在容器类上实现它应该很容易。

(如果适用,请查看Boost.Iterators库;它有iterator_facade和iterator_adaptor类来帮助您了解细节)