不可变的 C++ 容器类 [英] Immutable C++ container class
问题描述
假设我有一个 C++ 类 Container
,它包含一些 Element
类型的元素.由于各种原因,在施工后对内容进行修改或替换是低效的、不可取的、不必要的、不切实际的和/或不可能的(1).类似于 const std::list
(2).
Say that I have a C++ class, Container
, that contains some elements of type Element
. For various reasons, it is inefficient, undesirable, unnecessary, impractical, and/or impossible (1) to modify or replace the contents after construction. Something along the lines of const std::list<const Element>
(2).
Container
可以满足 STL 的容器"和序列"概念的许多要求.它可以提供各种类型,如value_type
、reference
等.它可以提供一个默认构造函数、一个复制构造函数、一个const_iterator
类型、begin() const
、end() const
、size
、empty
,所有的比较运算符,也许还有一些rbegin() const
、rend() const
、front()
、back()
、operator[]()
和 at()
.
Container
can meet many requirements of the STL's "container" and "sequence" concepts. It can provide the various types like value_type
, reference
, etc. It can provide a default constructor, a copy constructor, a const_iterator
type, begin() const
, end() const
, size
, empty
, all the comparison operators, and maybe some of rbegin() const
, rend() const
, front()
, back()
, operator[]()
, and at()
.
然而,Container
不能提供insert
、erase
、clear
、push_front代码>、
push_back
、非常量front
、非常量back
、非常量operator[]
、或具有预期语义的非常量 at
.所以看起来 Container
不能作为序列".此外,Container
不能提供 operator=
和 swap
,也不能提供 iterator
类型指向一个非常量元素.因此,它甚至不能称为容器".
However, Container
can't provide insert
, erase
, clear
, push_front
, push_back
, non-const front
, non-const back
, non-const operator[]
, or non-const at
with the expected semantics. So it appears that Container
can't qualify as a "sequence". Further, Container
can't provide operator=
, and swap
, and it can't provide an iterator
type that points to a non-const element. So, it can't even qualify as a "container".
Container
是否遇到了一些功能较弱的 STL 概念?是否有只读容器"或不可变容器"?
Is there some less-capable STL concept that Container
meets? Is there a "read-only container" or an "immutable container"?
如果 Container
不符合任何定义的一致性级别,部分一致性是否有价值?当它不符合条件时,使它看起来像一个容器"是否具有误导性?是否有一种简洁、明确的方式可以记录一致性,这样我就不必明确记录一致性语义?同样,一种记录它的方法,以便未来的用户知道他们可以利用只读的通用代码,但不要指望变异算法起作用?
If Container
doesn't meet any defined level of conformance, is there value in partial conformance? Is is misleading to make it look like a "container", when it doesn't qualify? Is there a concise, unambiguous way that I can document the conformance so that I don't have to explicitly document the conforming semantics? And similarly, a way to document it so that future users know they can take advantage of read-only generic code, but don't expect mutating algorithms to work?
如果我放宽问题使 Container
是可分配的(但它的元素不是),我会得到什么?此时,operator=
和 swap
是可能的,但是取消引用 iterator
仍然返回一个 const Element
.Container
现在是否符合容器"的要求?
What do I get if I relax the problem so Container
is Assignable (but its elements are not)? At that point, operator=
and swap
are possible, but dereferencing iterator
still returns a const Element
. Does Container
now qualify as a "container"?
const std::list
与 Container
具有大致相同的接口.这是否意味着它既不是容器"也不是序列"?
const std::list<T>
has approximately the same interface as Container
. Does that mean it is neither a "container" nor a "sequence"?
脚注 (1) 我有涵盖整个范围的用例.我有一个适用于一些只读数据的潜在容器类,因此它必须是不可变的.我有一个潜在的容器,可以根据需要生成自己的内容,因此它是可变的,但您不能按照 STL 要求的方式替换元素.我还有另一个可能的容器,它以一种方式存储它的元素,这种方式会使 insert()
变得如此缓慢,以至于它永远不会有用.最后,我有一个字符串,它以 UTF-8 格式存储文本,同时公开面向代码点的接口;可变实现是可能的,但完全没有必要.
Footnote (1) I have use cases that cover this whole spectrum. I have a would-be-container class that adapts some read-only data, so it has to be immutable. I have a would-be-container that generates its own contents as needed, so it's mutable but you can't replace elements the way the STL requires. I yet have another would-be-container that stores its elements in a way that would make insert()
so slow that it would never be useful. And finally, I have a string that stores text in UTF-8 while exposing a code-point oriented interface; a mutable implementation is possible but completely unnecessary.
脚注 (2) 这只是为了说明.我很确定 std::list
需要一个可分配的元素类型.
Footnote (2) This is just for illustration. I'm pretty sure std::list
requires an assignable element type.
推荐答案
STL 没有定义任何次要的概念;主要是因为 const
的想法通常在每个迭代器或每个引用级别上表达,而不是在每个类级别上.
The STL doesn't define any lesser concepts; mostly because the idea of const
is usually expressed on a per-iterator or per-reference level, not on a per-class level.
你不应该提供具有意外语义的iterator
,只提供const_iterator
.这允许客户端代码在出错时在最合乎逻辑的位置(带有最易读的错误消息)失败.
You shouldn't provide iterator
with unexpected semantics, only provide const_iterator
. This allows client code to fail in the most logical place (with the most readable error message) if they make a mistake.
可能最简单的方法是封装它并防止所有非常量别名.
Possibly the easiest way to do it would be to encapsulate it and prevent all non-const aliases.
class example {
std::list<sometype> stuff;
public:
void Process(...) { ... }
const std::list<sometype>& Results() { return stuff; }
};
现在任何客户端代码都确切地知道他们可以对需要变异的 Resultsnada 的返回值做什么.
Now any client code knows exactly what they can do with the return value of Results- nada that requires mutation.
这篇关于不可变的 C++ 容器类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!