非默认可构造元素的最后一个元素

Posted

技术标签:

【中文标题】非默认可构造元素的最后一个元素【英文标题】:Past-the-last element for non default-constructible elements 【发布时间】:2017-10-10 16:18:48 【问题描述】:

在使用类 STL 接口的树类上工作时,我遇到了使用不可默认构造元素的问题:

在实现迭代器时,我需要在任何时间点都有一个过去最后一个元素。我的方法是在构造函数中创建一个,它断言值类型是默认可构造的。

有没有办法摆脱这个限制?

【问题讨论】:

新的安置可以避免你过早的建设......只是说 过去的结束元素不应该存在。 当你说过去的最后一个元素时,也许你的意思是一个end 元素,对于原始数组来说,它可能是一个指向最后一个元素的指针,但不是必须的。您可以使用一些哨兵类型来表示“结束”。 没有过去的元素是我的第一个方法。就基于指针的树而言,这自然是一个 nullptr。问题发生在我尝试实现双向迭代器的那一刻。我应该如何从过去的最后一个迭代器中找到最后一个元素? 一些STL实现采用的解决方案是有一个不包含任何元素的过去最后一个节点。 Tbis 需要有两种节点类型,通常来自一个共同的基础。 【参考方案1】:

如果您的迭代器是双向的,则指向末尾不可能是 nullptrend()-- 必须是合法的。

它可以由哨兵实现,在这种情况下,哨兵甚至不应该包含默认构造的元素。

这样就可以了

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 publicly 继承自 linklink 也可以访问,但它不应该访问。 @nwp link 当然应该隐藏在一些实现命名空间中,为什么我需要的不仅仅是一个原始指针? Here 是使用上述相同想法的双向链表的玩具实现。由于我很懒,没有const_iterator,所以有点问题【参考方案2】:

我通过存储另一个指向根节点的指针解决了这个问题,我可以在恒定时间内重新创建最后一个元素。

【讨论】:

以上是关于非默认可构造元素的最后一个元素的主要内容,如果未能解决你的问题,请参考以下文章

不需要其元素为默认且可复制构造的容器

多线程(十八阻塞队列-ArrayBlockingQueue)

行内元素和块级元素、替换元素和非替换元素

如何避免在thrust::device_vector 中默认构造元素?

两个队列模拟一个栈行为;

Swing组件