C ++ Safe返回指向迭代器的指针以进行地图插入?

时间:2013-06-07 15:47:05

标签: c++ pointers iterator

所以我有一些C ++类使用map和key类来处理某种数据结构。在我的插入方法中,我使用典型的map.insert。我希望这个函数返回一个指针,这样我就可以在插入的元素中修改一些值(不是用于比较的值)。所以我想知道这对这是否安全..

template<typename T>
NodeT<T> *  TreeT<T>::
MakeNode(PointT point)
{
  NodeT<T> * prNode = new NodeT<T>;

    //set the contents for the node
  prNode->SetNode(point, m_dTolerance);


  //Create the key class using the 
  VectorKey key(point, m_dTolerance);

  //Store the key,node as a pair for easy access 
  return_val = m_tree.insert( pair<VectorKey, NodeT<T> >(key, *prNode) );
  if (return_val.second == false)
    //if return_val.second is false it wasnt inserted
    prNode = NULL;
  else
   //it was inserted, get a pointer to node
    prNode = &(return_val.first->second); //is this safe if I plan to use it later?

  return prNode;

}

我似乎学习了我的原始指针(我用new创建的那个)在插入后指向错误元素的困难方式。谁能告诉我为什么会这样?所以我使用return_val迭代器来获取正确的指针。我有点不想要返回迭代器但是如果它更安全那么我会...

谢谢!

3 个答案:

答案 0 :(得分:2)

您的代码中似乎有指针和值的麻烦。首先在堆上分配一个对象(使用新节点) 然后使用该对象的副本在地图中疼痛。 PS。然后你永远松开原始物体,因为没有释放内存导致内存泄漏。

在您的情况下 - 它是无效的,因为您返回指向对象的指针,可以随时删除(例如,下次向地图添加内容并且地图决定重新分配它的树,因此它会将对象复制到不同的地方)。 将指针存储为映射值会阻止这种情况。在从地图中删除对象以及删除地图本身时,您唯一需要记住清除它们。 处理它的简单方法是使用智能指针(例如boost :: shared_ptr)或智能地图类(例如boost :: ptr_map)。

要解决此问题 - 在任何地方使用指针(将指针存储为地图值)。 这样 - 您将能够从此函数返回指针,它将是有效的。 所以只需将地图转换为地图*&gt;这应该解决你的大多数问题。 从地图上删除对象时,不要伪造删除对象。

答案 1 :(得分:1)

此代码示例很有趣,因为包含一些错误或要避免的错误。

<强>实施

最重要的事情已经说过(主要是博格特):

  • 你正在泄漏内存,因为从堆中分配NodeT<T>并且永远不会再释放它,因为map将分配对象的副本,而不是指针。实际上,您指定为参数*prNode,而不是prNode
  • 您使用堆来分配对象(将被复制到map),但您假设您始终分配对象。尽管它将是最可能的情况,但这并非总是如此:new运算符将返回null或抛出bad_alloc异常。代码无法处理它。
  • 无论如何,在不需要时使用堆。 (而且你看到问题是你因为那而引人入胜)。您只需在堆栈中创建对象,然后插入到地图中,避免以前的问题并输入更少的代码。

<强>设计

  • 该函数返回指向地图中元素的指针。根据程序,这是安全的。但是,如果代码在从地图中删除对象时引用指针会发生什么?更好的是,如果要返回指针,请不要返回原始指针。使用智能指针(在这种情况下为shared_ptr)。使用shared_ptr您将不会遇到对象生命问题。
  • 使用智能指针的其他原因:因为插入到地图中意味着元素的副本,所以要求NodeT<T>:它必须是可复制构造的。可能这个要求对于性能并不重要,但可能在其他情况下复制对象有缺点。如果您使用智能指针(或boost::ptr_map),该对象将只创建一次而不会被复制。

<强>风格

只是一些建议,但不是太重要:

  • 改为键入pair<VectorKey, NodeT<T> >(key, *prNode),键入make_pair(key, *prNode)。代码更紧凑,更清晰,打字更少。

答案 2 :(得分:0)

好吧,我会说这取决于你的地图是否比可以使用(并存储)指针的任何东西活着更久。

如果是,(即,它是某种单身),你可以使用它,但不管怎样都不安全,因为任何代码都可以删除指针。

最好的选择是存储boost :: shared_ptr(或std :: since c ++ 11)而不是mapn中的原始指针,并在插入后仅返回weak_ptr。

这样,只要地图保存了指针就确定没有其他代码可以删除指针,并且没有人可以使用已从地图中删除的指针。