假设我有一个C ++类Container
,它包含一些Element
类型的元素。由于各种原因,在构造之后修改或替换内容是低效的,不合需要的,不必要的,不切实际的和/或不可能的(1)。类似于const std::list<const Element>
(2)的行。
Container
可以满足STL的“容器”和“序列”概念的许多要求。它可以提供各种类型,例如value_type
,reference
等。它可以提供默认构造函数,复制构造函数,const_iterator
类型,begin() const
,{{1} },end() const
,size
,所有比较运算符,可能还有一些empty
,rbegin() const
,rend() const
,front()
,{{1 }和back()
。
但是,operator[]()
无法提供at()
,Container
,insert
,erase
,clear
,非常量{{1具有预期语义的非常量push_front
,非常量push_back
或非常量front
。因此back
似乎不能作为“序列”。此外,operator[]
无法提供at
和Container
,并且无法提供指向非const元素的Container
类型。因此,它甚至不能成为“容器”。
operator=
会遇到一些功能较弱的STL概念吗?是否有“只读容器”或“不可变容器”?
如果swap
不符合任何规定的一致性水平,那么部分一致性是否有价值?当它没有资格时,是否会误导它看起来像一个“容器”?是否有一种简洁,明确的方式可以记录一致性,这样我就不必明确记录符合要求的语义?同样,一种记录它的方法,以便未来的用户知道他们可以利用只读的通用代码,但是不要指望变异算法有效吗?
如果我放松了这个问题,iterator
是可分配的(但它的元素不是),我会得到什么?此时,Container
和Container
是可能的,但取消引用Container
仍会返回operator=
。 swap
现在是否有资格成为“容器”?
iterator
与const Element
的界面大致相同。这是否意味着它既不是“容器”也不是“序列”?
脚注(1)我有覆盖整个频谱的用例。我有一个容器类可以调整一些只读数据,所以它必须是不可变的。我有一个容器,可以根据需要生成自己的内容,所以它是可变的,但你不能像STL所要求的那样替换元素。我还有另一个容器,它以一种使Container
如此慢以至于永远无用的方式存储其元素。最后,我有一个字符串,以UTF-8存储文本,同时公开面向代码点的接口;可变的实现是可能的,但完全没有必要。
脚注(2)这只是为了说明。我很确定const std::list<T>
需要一个可赋值的元素类型。
答案 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类来帮助您了解细节)