【问题标题】:C++ design issue with unordered_set and iteratorsunordered_set 和迭代器的 C++ 设计问题
【发布时间】:2016-10-17 15:12:05
【问题描述】:

我有以下sn-p

template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

const size_t INF(numeric_limits<size_t>::max());

class nodehasher;

class node{

public:
  int x,y;
  unordered_set<node, nodehasher>::iterator neighbs[6];  //Issue Here
  node(){}
  node(int x_, int y_):x(x_),y(y_){}
  void set(int x_, int y_){x = x_,y = y_;}
  bool operator == (const node &n)const{
    return x == n.x && y == n.y;
  }
};

class nodehasher{
  std::size_t operator()(node const& n) const{
    std::size_t seed = 0;
    hash_combine(seed, n.x);
    hash_combine(seed, n.y);
    return seed;
  }
};

我似乎在声明指向节点自身内的类节点的迭代器时遇到问题。

这会导致大量过于冗长的错误。

现在我意识到我可以创建我的邻居数组,一个指向节点的指针数组, 但出于明显的原因,我想避免使用指针

我使用它的典型简化方式是:

unordered_set<node, nodehasher> nodes;
void typical_use(node dest){
  auto src_node = node(0,0);
  int neighbcount = 0;
  auto iter = dest.insert(node).first;
  src_node.neighbs[neighb_count] = iter; 
}

我显然可以把它转换成指针然后做:

src_node.neighbs[neighb_count] = &(*iter);

但是有没有办法避免指向我想做的事情?

编辑:

正如许多 cmets 和答案所指出的那样,容器元素的指针和迭代器在重新散列后都会失效 所以存储它们是个坏主意。

我在想如果下面的方法有效,而不是节点的 unordered_set,我将使用指向节点的 unordered_set 指针,像这样

unordered_set<shared_ptr<node> > nodes;

另外,如果我知道节点的数量总是小于 500,我可以放弃整个哈希表的想法并使用一个数组,每次我都必须搜索数组以检查节点是否是已经在那里了。

您能指出哪种方法更好吗?

【问题讨论】:

  • 我不确定将迭代器存储在成员变量中是否明智。我不知道在你改变 unordered_set 之后事情是否会发生内部变化,然后迭代器会指向其他东西或者是意想不到的东西。
  • @Hayt 哦,天哪,我什至没有考虑过,看起来像是指针,谢谢,我应该删除问题吗?
  • 如果问题没有为您提供更多价值,您可以将其删除。您也可以尝试将问题改写/编辑到您想知道没有迭代器数组部分的指针的替代方案。
  • 如果您不知道容器何时会使它们失效,那么指针和迭代器都可能很危险。见stackoverflow.com/questions/6438086/iterator-invalidation-rules

标签: c++ iterator


【解决方案1】:

标准容器需要完整的值类型。 node 在您使用它来实例化 unordered_set&lt;node, nodehasher&gt; 时不是完整类型。

你可以使用Boost.Container,因为它们允许不完整的类型,但我看不到散列容器(所以你必须使用set)。

不过,您应该小心存储迭代器,因为至少对于标准库中的 unordered_ 容器,它们可能会在 重新散列。引用(和指针)不会失效。

【讨论】:

  • 我可以为此使用智能指针吗?是否有适合此目的的智能指针?
  • 你可以,但它很容易以循环依赖而告终。如果您将指针视为仅观察者的指针,那么您应该可以使用它们,特别是因为所有节点都属于容器,因此它们的生命周期是众所周知的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
  • 2013-09-13
  • 2015-09-30
  • 2012-12-08
  • 1970-01-01
相关资源
最近更新 更多