非默认可构造元素的最后一个元素
Posted
技术标签:
【中文标题】非默认可构造元素的最后一个元素【英文标题】:Past-the-last element for non default-constructible elements 【发布时间】:2017-10-10 16:18:48 【问题描述】:在使用类 STL 接口的树类上工作时,我遇到了使用不可默认构造元素的问题:
在实现迭代器时,我需要在任何时间点都有一个过去最后一个元素。我的方法是在构造函数中创建一个,它断言值类型是默认可构造的。
有没有办法摆脱这个限制?
【问题讨论】:
新的安置可以避免你过早的建设......只是说 过去的结束元素不应该存在。 当你说过去的最后一个元素时,也许你的意思是一个end
元素,对于原始数组来说,它可能是一个指向最后一个元素的指针,但不是必须的。您可以使用一些哨兵类型来表示“结束”。
没有过去的元素是我的第一个方法。就基于指针的树而言,这自然是一个 nullptr。问题发生在我尝试实现双向迭代器的那一刻。我应该如何从过去的最后一个迭代器中找到最后一个元素?
一些STL实现采用的解决方案是有一个不包含任何元素的过去最后一个节点。 Tbis 需要有两种节点类型,通常来自一个共同的基础。
【参考方案1】:
如果您的迭代器是双向的,则指向末尾不可能是 nullptr
,end()--
必须是合法的。
它可以由哨兵实现,在这种情况下,哨兵甚至不应该包含默认构造的元素。
这样就可以了
struct link
link *parent, *left, *right;
;
template<typename T>
struct node : link
T data;
;
template<typename T>
struct tree : link
// tree itself serves as the sentinel
// At initialization parent and childs should all point to the sentinel
tree() : parent(this), left(this), right(this)
// ...
;
并且迭代器不需要对结束情况进行特殊处理。
// nested within tree
struct iterator
explicit iterator(link* l) : n(l)
iterator& operator--() n = n->parent; return *this; // or something else
auto& operator*() return reinterpret_cast<node<T>*>(n)->data;
// ...
link* n;
;
iterator begin() return left; // or something else
iterator end() return this;
【讨论】:
您完全可以将迭代器类型设为nullptr
。您只需要在operator--()
中添加一个检查。可以说这比将节点类型泄漏到客户端代码中要好。
@nwp 节点类型没有泄露,查看tree
的接口。你如何从nullptr
倒退?假设你有两棵树,你怎么知道你指的是哪个end()
?注意迭代器只有一个指针,没有另一个指向树本身
这是我一直在寻找的通用解决方案,@PasserBy!
无论如何,您都不能将原始指针用于树。你需要像struct Iterator Node *node; ;
这样的东西才能完全实现operator--()
并且Iteratornullptr;
作为过去的迭代器值工作得很好。据我所见,tree
public
ly 继承自 link
和 link
也可以访问,但它不应该访问。
@nwp link
当然应该隐藏在一些实现命名空间中,为什么我需要的不仅仅是一个原始指针? Here 是使用上述相同想法的双向链表的玩具实现。由于我很懒,没有const_iterator
,所以有点问题【参考方案2】:
我通过存储另一个指向根节点的指针解决了这个问题,我可以在恒定时间内重新创建最后一个元素。
【讨论】:
以上是关于非默认可构造元素的最后一个元素的主要内容,如果未能解决你的问题,请参考以下文章
多线程(十八阻塞队列-ArrayBlockingQueue)