[英]When creating my own data structure, should I use iterators or indices to provide access from the outside?
假设我正在用现代版本的C ++(例如11或14)编写一个项目,并在该项目中使用STL。 在某个时刻,我需要对可以使用STL容器构建的特定数据结构进行编程。 DS封装在一个类中(对吗,将DS封装在一个类中是在C ++中对其进行编码的唯一正确方法吗?),因此我需要提供某种接口来提供对该对象的读和/或写访问。数据。 这就引出了一个问题:
我应该为此使用(1a)迭代器还是(1b)简单的“索引”(即某种类型的数字)? 我现在正在使用的DS几乎是线性的,但是当元素被删除时,简单的整数索引当然会失效。 那是我能想到的唯一反对这种方法的论点。
哪种方法更惯用? 支持和反对每一个的客观技术论据是什么?
另外,当我选择对自定义DS使用迭代器时,我应该(2a) public
对内部使用的容器的迭代器进行typedef
定义,还是(2b)从头开始创建自己的迭代器? 在Boost等开放库中,我看到了自定义迭代器是从头开始编写的。 另一方面,我觉得我还不能编写适当的迭代器(即,与STL和/或Boost中的迭代器一样详细和复杂的迭代器)。
根据@πάνταῥεῖ请求编辑 :
在大学学习时,我在几个项目中用几个DS问了自己这个问题,但这是最后一次让我来这里问问题的情况。
DS旨在表示三角形数组或顶点数组,或任何可能称为三角形的数组。 点是,有两个数组或列表,一个数组或列表存储顶点坐标,另一个数组或列表存储来自第一个数组的索引的三元组,因此代表三角形。 (这已经被编码了数百亿次,但是为了学习的目的,我想一次写一次。)显然,两个数组应该保持同步,因此是封装。 该组操作旨在包括使用同一数组中的顶点数据来添加(或也可以删除)顶点,添加和删除三角形(顶点三元组)。 我看到的是客户端添加顶点,写下索引/迭代器,然后发出调用以基于这些索引/迭代器添加三角形,这又将另一个索引/迭代器返回到生成的三角形。
哪种方法更惯用?
使用迭代器绝对是必经之路。 <algorithm>
函数不适用于索引。 他们使用迭代器。 如果希望容器启用以供<algorithm>
的函数使用,则使用迭代器是唯一的方法。
通常,建议类提供自己的迭代器。 在后台,它可以是索引或STL迭代器(首选)。 但是,只要涉及外部客户端和公共API,它们仅处理该类提供的迭代器。
例子1
class Dictionary {
private:
typedef std::unordered_map<string, string> DictType;
public:
typedef DictType::iterator DictionaryIterator;
};
例子2
class Sequence {
private:
typedef std::vector<string> SeqType;
public:
struct SeqIterator {
size_t index;
SeqIterator operator++();
string operator*();
};
};
如果客户端仅在SeqIterator
上SeqIterator
,则可以稍后将上述内容修改为
class Sequence {
private:
typedef std::deque<string> SeqType;
public:
typedef SeqType::iterator SeqIterator;
};
不会影响客户。
std::vector
具有迭代器和at
/ operator[]
方法来提供索引访问。
容器的API取决于您要向客户端提供的操作。
容器是否可迭代,即可以迭代每个元素? 然后,您应该提供一个迭代器。
知道它们的地址,随机访问容器中的元素是否有意义? 然后,您还可以提供at(size_t)
/ operator[size_t]
方法。
知道一个特殊的“键”来随机访问容器中的元素是否有意义? 您可能应该提供at(key_type)
/ operator[key_type]
方法。
至于您有关自定义迭代器或现有迭代器重用的问题:
如果您的容器基本上是为现有容器添加一些插入/移除逻辑的包装器,那么我认为公开定义现有迭代器是可以的,因为自定义迭代器可能会遗漏现有迭代器的某些功能,可能包含错误以及不会在现有的迭代器上添加任何重要功能。
另一方面,如果您以非标准的方式进行迭代(例如,我实施了一次recursive_unordered_map
,该recursive_unordered_map
在构造时接受了父级recursive_unordered_map
,并且会在其自身的unordered_map
和其父级(以及其父级的父级... )。为此,我必须实现一个自定义迭代器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.